From 73c69e8eda4ade55ea95c89a9062340376918af4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 25 Sep 2012 02:35:50 +0200 Subject: [PATCH 001/916] video playback --- apps/openmw/CMakeLists.txt | 7 +- apps/openmw/mwbase/world.hpp | 4 + apps/openmw/mwgui/mode.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 3 + apps/openmw/mwrender/renderingmanager.cpp | 11 + apps/openmw/mwrender/renderingmanager.hpp | 5 + apps/openmw/mwrender/videoplayer.cpp | 395 ++++++++++++++++++++++ apps/openmw/mwrender/videoplayer.hpp | 105 ++++++ apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/miscextensions.cpp | 16 + apps/openmw/mwworld/worldimp.cpp | 5 + apps/openmw/mwworld/worldimp.hpp | 3 + files/gbuffer/gbuffer.compositor | 2 +- 13 files changed, 559 insertions(+), 4 deletions(-) create mode 100644 apps/openmw/mwrender/videoplayer.cpp create mode 100644 apps/openmw/mwrender/videoplayer.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 66844b280..da1b3e15d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows - compositors characterpreview externalrendering globalmap + compositors characterpreview externalrendering globalmap videoplayer ) add_openmw_dir (mwinput @@ -108,6 +108,11 @@ target_link_libraries(openmw components ) +if (USE_FFMPEG) + target_link_libraries(openmw + "swscale") +endif() + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 521bbb988..0ba4b84dd 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -291,6 +291,10 @@ namespace MWBase /// 1 - only waiting \n /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + + + /// \todo this does not belong here + virtual void playVideo(const std::string& name) = 0; }; } diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 64aa1dc21..74ecd531a 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -41,7 +41,9 @@ namespace MWGui GM_Loading, GM_LoadingWallpaper, - GM_QuickKeysMenu + GM_QuickKeysMenu, + + GM_Video }; // Windows shown in inventory mode diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5a04a90c0..6ff4cee07 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -371,6 +371,9 @@ void WindowManager::updateVisible() case GM_Loading: MyGUI::PointerManager::getInstance().setVisible(false); break; + case GM_Video: + mHud->setVisible(false); + break; default: // Unsupported mode, switch back to game break; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index f0833e82d..98fc4175e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -36,6 +36,7 @@ #include "npcanimation.hpp" #include "externalrendering.hpp" #include "globalmap.hpp" +#include "videoplayer.hpp" using namespace MWRender; using namespace Ogre; @@ -159,6 +160,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); + mVideoPlayer = new VideoPlayer(mRendering.getScene ()); + mSun = 0; mDebugging = new Debugging(mMwRoot, engine); @@ -180,6 +183,7 @@ RenderingManager::~RenderingManager () delete mOcclusionQuery; delete mCompositors; delete mWater; + delete mVideoPlayer; } MWRender::SkyManager* RenderingManager::getSkyManager() @@ -339,6 +343,8 @@ void RenderingManager::update (float duration) mRendering.update(duration); + mVideoPlayer->update (); + MWWorld::RefData &data = MWBase::Environment::get() .getWorld() @@ -898,4 +904,9 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend rendering.setup (mRendering.getScene()); } +void RenderingManager::playVideo(const std::string& name) +{ + mVideoPlayer->play ("video/" + name); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 359809b71..d0ef3f593 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -45,6 +45,7 @@ namespace MWRender class Compositors; class ExternalRendering; class GlobalMap; + class VideoPlayer; class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { @@ -195,6 +196,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setupExternalRendering (MWRender::ExternalRendering& rendering); + void playVideo(const std::string& name); + protected: virtual void windowResized(Ogre::RenderWindow* rw); virtual void windowClosed(Ogre::RenderWindow* rw); @@ -248,6 +251,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList MWRender::Shadows* mShadows; MWRender::Compositors* mCompositors; + + VideoPlayer* mVideoPlayer; }; } diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp new file mode 100644 index 000000000..04a6de30b --- /dev/null +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -0,0 +1,395 @@ +#include "videoplayer.hpp" + +//#ifdef OPENMW_USE_FFMPEG + +#include +#include +#include +#include + + +extern "C" +{ +#include +#include +#include +} + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + + +namespace MWRender +{ + + int OgreResource_Read(void *opaque, uint8_t *buf, int buf_size) + { + Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + + int num_read = stream->size() - stream->tell(); + + if (num_read > buf_size) + num_read = buf_size; + + stream->read(buf, num_read); + return num_read; + } + + int OgreResource_Write(void *opaque, uint8_t *buf, int buf_size) + { + Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + + int num_write = stream->size() - stream->tell(); + + if (num_write > buf_size) + num_write = buf_size; + + stream->write (buf, num_write); + return num_write; + } + + int64_t OgreResource_Seek(void *opaque, int64_t offset, int whence) + { + Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + + switch (whence) + { + case SEEK_SET: + stream->seek(offset); + case SEEK_CUR: + stream->seek(stream->tell() + offset); + case SEEK_END: + stream->seek(stream->size() + offset); + case AVSEEK_SIZE: + return stream->size(); + default: + return -1; + } + + return stream->tell(); + } + + VideoPlayer::VideoPlayer(Ogre::SceneManager *sceneMgr) + : mAvContext(NULL) + , mVideoStreamId(-1) + { + Ogre::MaterialPtr videoMaterial = Ogre::MaterialManager::getSingleton ().create("VideoMaterial", "General"); + videoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + videoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + videoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + mTextureUnit = videoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(); + + mRectangle = new Ogre::Rectangle2D(true); + mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); + mRectangle->setMaterial("VideoMaterial"); + mRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY+1); + // Use infinite AAB to always stay visible + Ogre::AxisAlignedBox aabInf; + aabInf.setInfinite(); + mRectangle->setBoundingBox(aabInf); + // Attach background to the scene + Ogre::SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); + node->attachObject(mRectangle); + mRectangle->setVisible(false); + mRectangle->setVisibilityFlags (0x1); + } + + VideoPlayer::~VideoPlayer() + { + if (mAvContext) + deleteContext(); + + delete mRectangle; + } + + void VideoPlayer::play (const std::string& resourceName) + { + mStream = Ogre::ResourceGroupManager::getSingleton ().openResource (resourceName); + + + mVideoStreamId = -1; + mEOF = false; + + // if something is already playing, close it + if (mAvContext) + close(); + + mRectangle->setVisible(true); + + MWBase::Environment::get().getWindowManager ()->pushGuiMode (MWGui::GM_Video); + + + // BASIC INITIALIZATION + + // Load all the decoders + av_register_all(); + + AVIOContext *ioContext = 0; + + int err = 0; + + mAvContext = avformat_alloc_context(); + if (!mAvContext) + throwError(0); + + ioContext = avio_alloc_context(NULL, 0, 0, &mStream, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if (!ioContext) + throwError(0); + + mAvContext->pb = ioContext; + + err = avformat_open_input(&mAvContext, resourceName.c_str(), NULL, NULL); + if (err != 0) + throwError(err); + + err = avformat_find_stream_info(mAvContext, 0); + if (err < 0) + throwError(err); + + + + + // INIT VIDEO + + // Find the video stream among the different streams + for (unsigned int i = 0; i < mAvContext->nb_streams; i++) + { + if (mAvContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) + { + mVideoStreamId = i; + break; + } + } + + if (-1 == mVideoStreamId) + throw std::runtime_error("No video stream found in the video"); + + // Get the video codec + mVideoCodecContext = mAvContext->streams[mVideoStreamId]->codec; + if (!mVideoCodecContext) + throw std::runtime_error("Stream doesn't have a codec"); + + // Get the video decoder + mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id); + if (NULL == mVideoCodec) + throw std::runtime_error("No decoder found"); + + // Load the video codec + err = avcodec_open2(mVideoCodecContext, mVideoCodec, 0); + if (err < 0) + throwError (err); + + // Create the frame buffers + mRawFrame = avcodec_alloc_frame(); + mRGBAFrame = avcodec_alloc_frame(); + if (!mRawFrame || !mRGBAFrame) + { + throw std::runtime_error("Can't allocate video frames"); + } + + + avpicture_alloc ((AVPicture *)mRGBAFrame, PIX_FMT_RGBA, mVideoCodecContext->width, mVideoCodecContext->height); + + + // Setup the image scaler + // All this does is convert from YUV to RGB - note it would be faster to do this in a shader, + // but i'm not worried about performance just yet + mSwsContext = sws_getContext(mVideoCodecContext->width, mVideoCodecContext->height, + mVideoCodecContext->pix_fmt, + mVideoCodecContext->width, mVideoCodecContext->height, + PIX_FMT_RGBA, + SWS_BICUBIC, NULL, NULL, NULL); + if (!mSwsContext) + throw std::runtime_error("Can't create SWS Context"); + + // Get the frame time we need for this video + AVRational r = mAvContext->streams[mVideoStreamId]->avg_frame_rate; + AVRational r2 = mAvContext->streams[mVideoStreamId]->r_frame_rate; + if ((!r.num || !r.den) && + (!r2.num || !r2.den)) + { + std::cerr << "Warning - unable to get the video frame rate. Using standard NTSC frame rate : 29.97 fps." << std::endl; + mWantedFrameTime = 1.f / 29.97f; + } + else + { + if (r.num && r.den) + mWantedFrameTime = 1.f/((float)r.num / r.den); + else + mWantedFrameTime = 1.f/((float)r2.num / r2.den); + } + + + mTextureUnit->setTextureName (""); + + if (!Ogre::TextureManager::getSingleton ().getByName("VideoTexture").isNull()) + Ogre::TextureManager::getSingleton().remove("VideoTexture"); + + mVideoTexture = Ogre::TextureManager::getSingleton().createManual( + "VideoTexture", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + mVideoCodecContext->width, mVideoCodecContext->height, + 0, + Ogre::PF_BYTE_RGBA, + Ogre::TU_DEFAULT); + + mTextureUnit->setTextureName ("VideoTexture"); + + } + + void VideoPlayer::throwError(int error) + { + char buffer[4096] = {0}; + + if (0 == av_strerror(error, buffer, sizeof(buffer))) + { + std::stringstream msg; + msg << "FFMPEG error: "; + msg << buffer << std::endl; + throw std::runtime_error(msg.str()); + } + else + throw std::runtime_error("Unknown FFMPEG error"); + } + + bool VideoPlayer::readFrameAndQueue () + { + bool ret = true; + AVPacket *pkt = NULL; + + // check we're not at eof + if (mEOF) + ret = false; + else + { + // read frame + pkt = (AVPacket *)av_malloc(sizeof(*pkt)); + int res = av_read_frame(mAvContext, pkt); + + // check we didn't reach eof right now + if (res < 0) + { + mEOF = true; + ret = false; + av_free(pkt); + } + else + { + // When a frame has been read, save it + if (!saveFrame(pkt)) + { + // we failed to save it, which means it was unknown type of frame - delete it here + av_free_packet(pkt); + av_free(pkt); + } + } + } + + return ret; + } + + bool VideoPlayer::saveFrame(AVPacket* frame) + { + bool saved = false; + + if (frame->stream_index == mVideoStreamId) + { + // If it was a video frame... + mVideoPacketQueue.push(frame); + saved = true; + } + + return saved; + + } + + void VideoPlayer::update() + { + if (!mAvContext) + return; + + + if (!mVideoPacketQueue.size() && mEOF) + close(); + + Ogre::Timer timer; + + if (!mVideoPacketQueue.size()) + { + if (readFrameAndQueue()) + decodeFrontFrame(); + } + else + decodeFrontFrame(); + + mDecodingTime = timer.getMilliseconds ()/1000.f; + } + + void VideoPlayer::decodeFrontFrame () + { + int didDecodeFrame = 0; + + // Make sure there is something to decode + if (!mVideoPacketQueue.size()) + return; + + // Get the front frame and decode it + AVPacket *videoPacket = mVideoPacketQueue.front(); + int res; + res = avcodec_decode_video2(mVideoCodecContext, mRawFrame, &didDecodeFrame, videoPacket); + + if (res < 0 || !didDecodeFrame) + throw std::runtime_error ("an error occured while decoding the video frame"); + + // Convert the frame to RGB + sws_scale(mSwsContext, + mRawFrame->data, mRawFrame->linesize, + 0, mVideoCodecContext->height, + mRGBAFrame->data, mRGBAFrame->linesize); + + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = mVideoTexture->getBuffer(); + Ogre::PixelBox pb(mVideoCodecContext->width, mVideoCodecContext->height, 1, Ogre::PF_BYTE_RGBA, mRGBAFrame->data[0]); + pixelBuffer->blitFromMemory(pb); + + //m_displayedFrameCount++; + av_free_packet(mVideoPacketQueue.front()); + av_free(mVideoPacketQueue.front()); + mVideoPacketQueue.pop(); + } + + void VideoPlayer::close () + { + mRectangle->setVisible (false); + MWBase::Environment::get().getWindowManager ()->removeGuiMode (MWGui::GM_Video); + deleteContext(); + } + + void VideoPlayer::deleteContext() + { + while (mVideoPacketQueue.size()) + { + av_free_packet(mVideoPacketQueue.front()); + av_free(mVideoPacketQueue.front()); + mVideoPacketQueue.pop(); + } + + avcodec_close(mVideoCodecContext); + + avpicture_free((AVPicture *)mRGBAFrame); + + if (mRawFrame) + av_free(mRawFrame); + if (mRGBAFrame) + av_free(mRGBAFrame); + + sws_freeContext(mSwsContext); + + avformat_close_input(&mAvContext); + + mAvContext = NULL; + } +} + +//#endif diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp new file mode 100644 index 000000000..05c04c96b --- /dev/null +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -0,0 +1,105 @@ +#ifndef MWRENDER_VIDEOPLAYER_H +#define MWRENDER_VIDEOPLAYER_H + +//#ifdef OPENMW_USE_FFMPEG + + + +#include + +#include +#include + +namespace Ogre +{ + class Rectangle2D; + class SceneManager; + class TextureUnitState; +} + +struct AVFormatContext; +struct AVCodecContext; +struct AVCodec; +struct AVFrame; +struct SwsContext; +struct AVPacket; + +namespace MWRender +{ + + class VideoPlayer + { + public: + VideoPlayer(Ogre::SceneManager* sceneMgr); + ~VideoPlayer(); + + void play (const std::string& resourceName); + + void update(); + + private: + Ogre::Rectangle2D* mRectangle; + Ogre::TextureUnitState* mTextureUnit; + + Ogre::DataStreamPtr mStream; + + Ogre::TexturePtr mVideoTexture; + + + private: + + AVFormatContext* mAvContext; + + + bool mEOF; + + // VIDEO + AVCodecContext* mVideoCodecContext; + AVCodec* mVideoCodec; + int mVideoStreamId; + AVFrame* mRawFrame; + AVFrame* mRGBAFrame; + SwsContext* mSwsContext; + float mWantedFrameTime; + float mDecodingTime; + std::queue mVideoPacketQueue; + + + bool readFrameAndQueue(); + bool saveFrame(AVPacket* frame); + + void decodeFrontFrame(); + + void close(); + void deleteContext(); + + + void throwError(int error); + }; + +} + +//#else +/* + + +// If FFMPEG not available, dummy implentation that does nothing + +namespace MWRender +{ + + class VideoPlayer + { + public: + VideoPlayer(Ogre::SceneManager* sceneMgr){} + + void play (const std::string& resourceName) {} + void update() {} + }; + +} +*/ +//#endif + + +#endif diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index a4a9e99fd..1c74a713f 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -205,5 +205,6 @@ op 0x200019e: PlaceAtMe Explicit op 0x200019f: GetPcSleep op 0x20001a0: ShowMap op 0x20001a1: FillMap -opcodes 0x20001a2-0x3ffffff unused +op 0x20001a2: PlayBink +opcodes 0x20001a3-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index a869f882b..330c1c79f 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -21,6 +21,19 @@ namespace MWScript { namespace Misc { + class OpPlayBink : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string name = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWBase::Environment::get().getWorld ()->playVideo (name); + } + }; + class OpGetPcSleep : public Interpreter::Opcode0 { public: @@ -261,6 +274,7 @@ namespace MWScript const int opcodeDontSaveObject = 0x2000153; const int opcodeToggleVanityMode = 0x2000174; const int opcodeGetPcSleep = 0x200019f; + const int opcodePlayBink = 0x20001a2; void registerExtensions (Compiler::Extensions& extensions) { @@ -286,6 +300,7 @@ namespace MWScript extensions.registerInstruction ("togglevanitymode", "", opcodeToggleVanityMode); extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode); extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep); + extensions.registerInstruction ("playbink", "S", opcodePlayBink); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -307,6 +322,7 @@ namespace MWScript interpreter.installSegment5 (opcodeDontSaveObject, new OpDontSaveObject); interpreter.installSegment5 (opcodeToggleVanityMode, new OpToggleVanityMode); interpreter.installSegment5 (opcodeGetPcSleep, new OpGetPcSleep); + interpreter.installSegment5 (opcodePlayBink, new OpPlayBink); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 834dffe79..06b58c183 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1281,4 +1281,9 @@ namespace MWWorld return 0; } + + void World::playVideo (const std::string &name) + { + mRendering->playVideo(name); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 90cd2151b..5d8c689db 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -322,6 +322,9 @@ namespace MWWorld /// 1 - only waiting \n /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + + /// \todo this does not belong here + virtual void playVideo(const std::string& name); }; } diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index 04600ce9b..0a0675fa0 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -72,7 +72,7 @@ compositor gbufferFinalizer pass render_scene { first_render_queue 51 - last_render_queue 100 + last_render_queue 105 } } target_output From 05eb307bfbe6b15ac39f5eae564b69797ba7f849 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 25 Sep 2012 02:54:29 +0200 Subject: [PATCH 002/916] added video timing --- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + apps/openmw/mwrender/videoplayer.cpp | 14 +++++++++++++- apps/openmw/mwrender/videoplayer.hpp | 5 +++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6ff4cee07..378003e39 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -372,6 +372,7 @@ void WindowManager::updateVisible() MyGUI::PointerManager::getInstance().setVisible(false); break; case GM_Video: + MyGUI::PointerManager::getInstance().setVisible(false); mHud->setVisible(false); break; default: diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 04a6de30b..195369a2d 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -109,6 +109,7 @@ namespace MWRender mVideoStreamId = -1; mEOF = false; + mDisplayedFrameCount = 0; // if something is already playing, close it if (mAvContext) @@ -236,6 +237,8 @@ namespace MWRender mTextureUnit->setTextureName ("VideoTexture"); + mTimer.reset(); + } void VideoPlayer::throwError(int error) @@ -309,6 +312,14 @@ namespace MWRender if (!mAvContext) return; + // Time elapsed since the video started + float realTime = mTimer.getMilliseconds ()/1000.f; + + // Here is the time we're at in the video + float movieTime = mDisplayedFrameCount * mWantedFrameTime; + + if (movieTime >= realTime) + return; if (!mVideoPacketQueue.size() && mEOF) close(); @@ -353,10 +364,11 @@ namespace MWRender Ogre::PixelBox pb(mVideoCodecContext->width, mVideoCodecContext->height, 1, Ogre::PF_BYTE_RGBA, mRGBAFrame->data[0]); pixelBuffer->blitFromMemory(pb); - //m_displayedFrameCount++; av_free_packet(mVideoPacketQueue.front()); av_free(mVideoPacketQueue.front()); mVideoPacketQueue.pop(); + + ++mDisplayedFrameCount; } void VideoPlayer::close () diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 05c04c96b..1d3010e8e 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace Ogre { @@ -53,6 +54,8 @@ namespace MWRender bool mEOF; + Ogre::Timer mTimer; + // VIDEO AVCodecContext* mVideoCodecContext; AVCodec* mVideoCodec; @@ -64,6 +67,8 @@ namespace MWRender float mDecodingTime; std::queue mVideoPacketQueue; + int mDisplayedFrameCount; + bool readFrameAndQueue(); bool saveFrame(AVPacket* frame); From 28d4d7ea3f3ad01bcd2ab35382cb7b3728a84d78 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 7 Oct 2012 20:00:55 +0200 Subject: [PATCH 003/916] Manually convert last changes in branch to upstream/master. Regular merge attempt resulted in everything being overwritten by fast-forward merging. - Remove check for 255 master/plugin files. --- apps/openmw/engine.cpp | 29 +++++++++++----- apps/openmw/engine.hpp | 8 +++-- apps/openmw/main.cpp | 21 ++++++------ apps/openmw/mwrender/terrain.cpp | 31 +++++++++++++---- apps/openmw/mwrender/terrain.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 33 ++++++++++++++---- apps/openmw/mwworld/worldimp.hpp | 3 +- components/esm/esm_reader.hpp | 8 +++++ components/esm/loadland.cpp | 1 + components/esm/loadland.hpp | 1 + components/esm_store/reclists.hpp | 56 +++++++++++++++++++++++++------ components/esm_store/store.cpp | 9 +++++ 12 files changed, 155 insertions(+), 47 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b86923a1d..a02dbf1d6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -212,18 +212,31 @@ void OMW::Engine::setCell (const std::string& cellName) // Set master file (esm) // - If the given name does not have an extension, ".esm" is added automatically -// - Currently OpenMW only supports one master at the same time. void OMW::Engine::addMaster (const std::string& master) { - assert (mMaster.empty()); - mMaster = master; - + mMaster.push_back(master); + std::string &str = mMaster.back(); + // Append .esm if not already there - std::string::size_type sep = mMaster.find_last_of ("."); + std::string::size_type sep = str.find_last_of ("."); if (sep == std::string::npos) { - mMaster += ".esm"; + str += ".esm"; + } +} + +// Add plugin file (esp) +void OMW::Engine::addPlugin (const std::string& plugin) +{ + mPlugins.push_back(plugin); + std::string &str = mPlugins.back(); + + // Append .esp if not already there + std::string::size_type sep = str.find_last_of ("."); + if (sep == std::string::npos) + { + str += ".esp"; } } @@ -331,8 +344,8 @@ void OMW::Engine::go() MWGui::CursorReplace replacer; // Create the world - mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); + mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, + mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap) ); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 57402c91e..7fd27b36b 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -64,7 +64,8 @@ namespace OMW boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; std::string mCellName; - std::string mMaster; + std::vector mMaster; + std::vector mPlugins; int mFpsLevel; bool mDebug; bool mVerboseScripts; @@ -122,9 +123,12 @@ namespace OMW /// Set master file (esm) /// - If the given name does not have an extension, ".esm" is added automatically - /// - Currently OpenMW only supports one master at the same time. void addMaster(const std::string& master); + /// Same as "addMaster", but for plugin files (esp) + /// - If the given name does not have an extension, ".esp" is added automatically + void addPlugin(const std::string& plugin); + /// Enable fps counter void showFPS(int level); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 5c2ba2f80..c2b8d7559 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -224,18 +224,19 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat master.push_back("Morrowind"); } - if (master.size() > 1) - { - std::cout - << "Ignoring all but the first master file (multiple master files not yet supported)." - << std::endl; - } - engine.addMaster(master[0]); - StringsVector plugin = variables["plugin"].as(); - if (!plugin.empty()) + // Removed check for 255 files, which would be the hard-coded limit in Morrowind. + // I'll keep the following variable in, maybe we can use it for somethng different. + int cnt = master.size() + plugin.size(); + + // Prepare loading master/plugin files (i.e. send filenames to engine) + for (std::vector::size_type i = 0; i < master.size(); i++) { - std::cout << "Ignoring plugin files (plugins not yet supported)." << std::endl; + engine.addMaster(master[i]); + } + for (std::vector::size_type i = 0; i < plugin.size(); i++) + { + engine.addPlugin(plugin[i]); } // startup-settings diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 691e7c4af..e39cdd150 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -141,7 +141,7 @@ namespace MWRender std::map indexes; initTerrainTextures(&terrainData, cellX, cellY, x * numTextures, y * numTextures, - numTextures, indexes); + numTextures, indexes, land->plugin); if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL) { @@ -200,8 +200,13 @@ namespace MWRender void TerrainManager::initTerrainTextures(Terrain::ImportData* terrainData, int cellX, int cellY, int fromX, int fromY, int size, - std::map& indexes) + std::map& indexes, size_t plugin) { + // FIXME: In a multiple esm configuration, we have multiple palettes. Since this code + // crosses cell boundaries, we no longer have a unique terrain palette. Instead, we need + // to adopt the following code for a dynamic palette. And this is evil - the current design + // does not work well for this task... + assert(terrainData != NULL && "Must have valid terrain data"); assert(fromX >= 0 && fromY >= 0 && "Can't get a terrain texture on terrain outside the current cell"); @@ -214,12 +219,20 @@ namespace MWRender // //If we don't sort the ltex indexes, the splatting order may differ between //cells which may lead to inconsistent results when shading between cells + int num = MWBase::Environment::get().getWorld()->getStore().landTexts.getSizePlugin(plugin); std::set ltexIndexes; for ( int y = fromY - 1; y < fromY + size + 1; y++ ) { for ( int x = fromX - 1; x < fromX + size + 1; x++ ) { - ltexIndexes.insert(getLtexIndexAt(cellX, cellY, x, y)); + int idx = getLtexIndexAt(cellX, cellY, x, y); + // This is a quick hack to prevent the program from trying to fetch textures + // from a neighboring cell, which might originate from a different plugin, + // and use a separate texture palette. Right now, we simply cast it to the + // default texture (i.e. 0). + if (idx > num) + idx = 0; + ltexIndexes.insert(idx); } } @@ -231,7 +244,7 @@ namespace MWRender iter != ltexIndexes.end(); ++iter ) { - const uint16_t ltexIndex = *iter; + uint16_t ltexIndex = *iter; //this is the base texture, so we can ignore this at present if ( ltexIndex == baseTexture ) { @@ -244,8 +257,12 @@ namespace MWRender { //NB: All vtex ids are +1 compared to the ltex ids - assert( (int)MWBase::Environment::get().getWorld()->getStore().landTexts.getSize() >= (int)ltexIndex - 1 && - "LAND.VTEX must be within the bounds of the LTEX array"); + // NOTE: using the quick hack above, we should no longer end up with textures indices + // that are out of bounds. However, I haven't updated the test to a multi-palette + // system yet. We probably need more work here, so we skip it for now. + + //assert( (int)MWBase::Environment::get().getWorld()->getStore().landTexts.getSize() >= (int)ltexIndex - 1 && + //"LAND.VTEX must be within the bounds of the LTEX array"); std::string texture; if ( ltexIndex == 0 ) @@ -254,7 +271,7 @@ namespace MWRender } else { - texture = MWBase::Environment::get().getWorld()->getStore().landTexts.search(ltexIndex-1)->texture; + texture = MWBase::Environment::get().getWorld()->getStore().landTexts.search(ltexIndex-1, plugin)->texture; //TODO this is needed due to MWs messed up texture handling texture = texture.substr(0, texture.rfind(".")) + ".dds"; } diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index c83d96cf4..484a0dbe3 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -75,7 +75,7 @@ namespace MWRender{ void initTerrainTextures(Ogre::Terrain::ImportData* terrainData, int cellX, int cellY, int fromX, int fromY, int size, - std::map& indexes); + std::map& indexes, size_t plugin); /** * Creates the blend (splatting maps) for the given terrain from the ltex data. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 38063b051..dd3717f97 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -164,7 +164,8 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, + const std::vector& master, const std::vector& plugins, + const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mNextDynamicRecord (0), mCells (mStore, mEsm), @@ -177,14 +178,32 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering); - boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master)); + int idx = 0; + for (std::vector::size_type i = 0; i < master.size(); i++, idx++) + { + boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); + + std::cout << "Loading ESM " << masterPath.string() << "\n"; - std::cout << "Loading ESM " << masterPath.string() << "\n"; + // This parses the ESM file + mEsm.setEncoding(encoding); + mEsm.open (masterPath.string()); + mEsm.setIndex(idx); + mStore.load (mEsm); + } + + for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) + { + boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i])); + + std::cout << "Loading ESP " << pluginPath.string() << "\n"; - // This parses the ESM file and loads a sample cell - mEsm.setEncoding(encoding); - mEsm.open (masterPath.string()); - mStore.load (mEsm); + // This parses the ESP file + mEsm.setEncoding(encoding); + mEsm.open (pluginPath.string()); + mEsm.setIndex(idx); + mStore.load (mEsm); + } mPlayer = new MWWorld::Player (mStore.npcs.find ("player"), *this); mRendering->attachCameraTo(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 90cd2151b..52bda6749 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -96,7 +96,8 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, + const std::vector& master, const std::vector& plugins, + const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, const std::string& encoding, std::map fallbackMap); virtual ~World(); diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 66c0710a6..afa6da213 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -189,6 +189,14 @@ public: void openRaw(const std::string &file); + // This is a quick hack for multiple esm/esp files. Each plugin introduces its own + // terrain palette, but ESMReader does not pass a reference to the correct plugin + // to the individual load() methods. This hack allows to pass this reference + // indirectly to the load() method. + int idx; + void setIndex(const int index) {idx = index;} + const int getIndex() {return idx;} + /************************************************************************* * * Medium-level reading shortcuts diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index 05cadae7f..101617071 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -23,6 +23,7 @@ Land::~Land() void Land::load(ESMReader &esm) { mEsm = &esm; + plugin = mEsm->getIndex(); // Get the grid location esm.getSubNameIs("INTV"); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index ebc314a28..898134d72 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -17,6 +17,7 @@ struct Land int flags; // Only first four bits seem to be used, don't know what // they mean. int X, Y; // Map coordinates. + int plugin; // Plugin index, used to reference the correct material palette. // File context. This allows the ESM reader to be 'reset' to this // location later when we are ready to load the full data set. diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index ffecfc8de..42597bea4 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -26,6 +26,7 @@ namespace ESMS virtual void load(ESMReader &esm, const std::string &id) = 0; virtual int getSize() = 0; + virtual void remove(const std::string &id) {}; virtual void listIdentifier (std::vector& identifier) const = 0; static std::string toLower (const std::string& name) @@ -57,6 +58,14 @@ namespace ESMS list[id2].load(esm); } + // Delete the given object ID. Plugin files support this, so we need to do this, too. + void remove(const std::string &id) + { + std::string id2 = toLower (id); + + list.erase(id2); + } + // Find the given object ID, or return NULL if not found. const X* search(const std::string &id) const { @@ -268,38 +277,63 @@ namespace ESMS { virtual ~LTexList() {} - // TODO: For multiple ESM/ESP files we need one list per file. - std::vector ltex; + // For multiple ESM/ESP files we need one list per file. + typedef std::vector LandTextureList; + std::vector ltex; LTexList() { - // More than enough to hold Morrowind.esm. - ltex.reserve(128); + ltex.push_back(LandTextureList()); + LandTextureList <exl = ltex[0]; + // More than enough to hold Morrowind.esm. Extra lists for plugins will we + // added on-the-fly in a different method. + ltexl.reserve(128); } - const LandTexture* search(size_t index) const + const LandTexture* search(size_t index, size_t plugin) const { - assert(index < ltex.size()); - return <ex.at(index); + assert(plugin < ltex.size()); + const LandTextureList <exl = ltex[plugin]; + + assert(index < ltexl.size()); + return <exl.at(index); } + // "getSize" returns the number of individual terrain palettes. + // "getSizePlugin" returns the number of land textures in a specific palette. int getSize() { return ltex.size(); } int getSize() const { return ltex.size(); } + int getSizePlugin(size_t plugin) { assert(plugin < ltex.size()); return ltex[plugin].size(); } + int getSizePlugin(size_t plugin) const { assert(plugin < ltex.size()); return ltex[plugin].size(); } + virtual void listIdentifier (std::vector& identifier) const {} - void load(ESMReader &esm, const std::string &id) + void load(ESMReader &esm, const std::string &id, size_t plugin) { LandTexture lt; lt.load(esm); lt.id = id; // Make sure we have room for the structure - if(lt.index + 1 > (int)ltex.size()) - ltex.resize(lt.index+1); + if (plugin >= ltex.size()) { + ltex.resize(plugin+1); + } + LandTextureList <exl = ltex[plugin]; + if(lt.index + 1 > (int)ltexl.size()) + ltexl.resize(lt.index+1); // Store it - ltex[lt.index] = lt; + ltexl[lt.index] = lt; + } + + // Load all terrain palettes at the same size. Inherited virtual function + // from "RecList". Mostly useless, because we need the implementation + // above this one. + void load(ESMReader &esm, const std::string &id) + { + size_t plugin = esm.getIndex(); + load(esm, id, plugin); } }; diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp index c676601e5..d13cd373d 100644 --- a/components/esm_store/store.cpp +++ b/components/esm_store/store.cpp @@ -67,6 +67,15 @@ void ESMStore::load(ESMReader &esm) { // Load it std::string id = esm.getHNOString("NAME"); + // ... unless it got deleted! This means that the following record + // has been deleted, and trying to load it using standard assumptions + // on the structure will (probably) fail. + if (esm.isNextSub("DELE")) { + esm.skipRecord(); + all.erase(id); + it->second->remove(id); + continue; + } it->second->load(esm, id); if (n.val==ESM::REC_DIAL) From 7f77bf76c7bc3e12fce4879b21612a6d49101fb7 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Tue, 6 Nov 2012 22:13:19 +0100 Subject: [PATCH 004/916] - Add support for multiple esm contexts in cell store. This will allow to generate references from multiple esX files. Currently, only the first context is used. - Add many TODOs to mark points where more work is required to fully implement this feature. --- apps/openmw/mwworld/cellstore.cpp | 128 +++++++++++++++++------------- apps/openmw/mwworld/cellstore.hpp | 4 + components/esm/loadcell.cpp | 12 ++- components/esm/loadcell.hpp | 3 +- extern/shiny | 2 +- 5 files changed, 89 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index fcdec1e7f..322b43a00 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -45,23 +45,32 @@ namespace MWWorld { assert (cell); - if (cell->mContext.filename.empty()) + if (cell->mContextList.size() == 0) return; // this is a dynamically generated cell -> skipping. - // Reopen the ESM reader and seek to the right position. - cell->restore (esm); - - ESM::CellRef ref; - - // Get each reference in turn - while (cell->getNextRef (esm, ref)) + // Load references from all plugins that do something with this cell. + // HACK: only use first entry for now, full support requires some more work + //for (int i = 0; i < cell->mContextList.size(); i++) + for (int i = 0; i < 1; i++) { - std::string lowerCase; + // Reopen the ESM reader and seek to the right position. + // TODO: we will need to intoduce separate "esm"s, one per plugin! + cell->restore (esm); - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + ESM::CellRef ref; - mIds.push_back (lowerCase); + // Get each reference in turn + while (cell->getNextRef (esm, ref)) + { + std::string lowerCase; + + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + // TODO: support deletion / moving references out of the cell. no simple "push_back", + // but see what the plugin wants to do. + mIds.push_back (lowerCase); + } } std::sort (mIds.begin(), mIds.end()); @@ -71,57 +80,64 @@ namespace MWWorld { assert (cell); - if (cell->mContext.filename.empty()) + if (cell->mContextList.size() == 0) return; // this is a dynamically generated cell -> skipping. - // Reopen the ESM reader and seek to the right position. - cell->restore(esm); - - ESM::CellRef ref; - - // Get each reference in turn - while(cell->getNextRef(esm, ref)) + // Load references from all plugins that do something with this cell. + // HACK: only use first entry for now, full support requires some more work + //for (int i = 0; i < cell->mContextList.size(); i++) + for (int i = 0; i < 1; i++) { - std::string lowerCase; + // Reopen the ESM reader and seek to the right position. + // TODO: we will need to intoduce separate "esm"s, one per plugin! + cell->restore(esm); - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + ESM::CellRef ref; - int rec = store.find(ref.mRefID); - - ref.mRefID = lowerCase; - - /* We can optimize this further by storing the pointer to the - record itself in store.all, so that we don't need to look it - up again here. However, never optimize. There are infinite - opportunities to do that later. - */ - switch(rec) + // Get each reference in turn + while(cell->getNextRef(esm, ref)) { - case ESM::REC_ACTI: activators.find(ref, store.activators); break; - case ESM::REC_ALCH: potions.find(ref, store.potions); break; - case ESM::REC_APPA: appas.find(ref, store.appas); break; - case ESM::REC_ARMO: armors.find(ref, store.armors); break; - case ESM::REC_BOOK: books.find(ref, store.books); break; - case ESM::REC_CLOT: clothes.find(ref, store.clothes); break; - case ESM::REC_CONT: containers.find(ref, store.containers); break; - case ESM::REC_CREA: creatures.find(ref, store.creatures); break; - case ESM::REC_DOOR: doors.find(ref, store.doors); break; - case ESM::REC_INGR: ingreds.find(ref, store.ingreds); break; - case ESM::REC_LEVC: creatureLists.find(ref, store.creatureLists); break; - case ESM::REC_LEVI: itemLists.find(ref, store.itemLists); break; - case ESM::REC_LIGH: lights.find(ref, store.lights); break; - case ESM::REC_LOCK: lockpicks.find(ref, store.lockpicks); break; - case ESM::REC_MISC: miscItems.find(ref, store.miscItems); break; - case ESM::REC_NPC_: npcs.find(ref, store.npcs); break; - case ESM::REC_PROB: probes.find(ref, store.probes); break; - case ESM::REC_REPA: repairs.find(ref, store.repairs); break; - case ESM::REC_STAT: statics.find(ref, store.statics); break; - case ESM::REC_WEAP: weapons.find(ref, store.weapons); break; + std::string lowerCase; - case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break; - default: - std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + int rec = store.find(ref.mRefID); + + ref.mRefID = lowerCase; + + /* We can optimize this further by storing the pointer to the + record itself in store.all, so that we don't need to look it + up again here. However, never optimize. There are infinite + opportunities to do that later. + */ + switch(rec) + { + case ESM::REC_ACTI: activators.find(ref, store.activators); break; + case ESM::REC_ALCH: potions.find(ref, store.potions); break; + case ESM::REC_APPA: appas.find(ref, store.appas); break; + case ESM::REC_ARMO: armors.find(ref, store.armors); break; + case ESM::REC_BOOK: books.find(ref, store.books); break; + case ESM::REC_CLOT: clothes.find(ref, store.clothes); break; + case ESM::REC_CONT: containers.find(ref, store.containers); break; + case ESM::REC_CREA: creatures.find(ref, store.creatures); break; + case ESM::REC_DOOR: doors.find(ref, store.doors); break; + case ESM::REC_INGR: ingreds.find(ref, store.ingreds); break; + case ESM::REC_LEVC: creatureLists.find(ref, store.creatureLists); break; + case ESM::REC_LEVI: itemLists.find(ref, store.itemLists); break; + case ESM::REC_LIGH: lights.find(ref, store.lights); break; + case ESM::REC_LOCK: lockpicks.find(ref, store.lockpicks); break; + case ESM::REC_MISC: miscItems.find(ref, store.miscItems); break; + case ESM::REC_NPC_: npcs.find(ref, store.npcs); break; + case ESM::REC_PROB: probes.find(ref, store.probes); break; + case ESM::REC_REPA: repairs.find(ref, store.repairs); break; + case ESM::REC_STAT: statics.find(ref, store.statics); break; + case ESM::REC_WEAP: weapons.find(ref, store.weapons); break; + + case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break; + default: + std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; + } } } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 32ab6e07b..fd739b565 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -62,6 +62,10 @@ namespace MWWorld if(obj == NULL) throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + // TODO: this line must be modified for multiple plugins and moved references. + // This means: no simple "push back", but search for an existing reference with + // this ID first! If it exists, merge data into this list instead of just adding it. + // I'll probably generate a separate method jist for this. list.push_back(LiveRef(ref, obj)); } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 97ce17775..65c9c23e7 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "esmreader.hpp" #include "esmwriter.hpp" @@ -111,7 +112,7 @@ void Cell::load(ESMReader &esm) } // Save position of the cell references and move on - mContext = esm.getContext(); + mContextList.push_back(esm.getContext()); esm.skipRecord(); } @@ -148,7 +149,8 @@ void Cell::save(ESMWriter &esm) void Cell::restore(ESMReader &esm) const { - esm.restoreContext(mContext); + // TODO: support all contexts in the list! + esm.restoreContext(mContextList[0]); } std::string Cell::getDescription() const @@ -167,6 +169,12 @@ std::string Cell::getDescription() const bool Cell::getNextRef(ESMReader &esm, CellRef &ref) { + // TODO: Add support for moved references. References moved without crossing a cell boundary simply + // overwrite old data. References moved across cell boundaries are using a different set of keywords, + // and I'll have to think more about how this can be done. + // TODO: Add support for multiple plugins. This requires a tricky renaming scheme for "ref.mRefnum". + // I'll probably add something to "ESMReader", we will need one per plugin anyway. + // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index fbd7c0456..9511ae0e7 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -2,6 +2,7 @@ #define OPENMW_ESM_CELL_H #include +#include #include "esmcommon.hpp" #include "defs.hpp" @@ -120,7 +121,7 @@ struct Cell // Optional region name for exterior and quasi-exterior cells. std::string mRegion; - ESM_Context mContext; // File position + std::vector mContextList; // File position; multiple positions for multiple plugin support DATAstruct mData; AMBIstruct mAmbi; float mWater; // Water level diff --git a/extern/shiny b/extern/shiny index f17c4ebab..4750676ac 160000 --- a/extern/shiny +++ b/extern/shiny @@ -1 +1 @@ -Subproject commit f17c4ebab0e7a1f3bbb25fd9b3dbef2bd742536a +Subproject commit 4750676ac46a7aaa86bca53dc68c5a1ba11f3bc1 From 42eefaf36ff371d8bdecdca54e5aa26269d7ba6b Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 10 Nov 2012 21:43:41 +0100 Subject: [PATCH 005/916] - Add support for loading references from multiple esm/esp files. Full reference ID mangling coming soon (currently, moved references are simply cloned). - Reference loader now (partially) supports MVRF tag. --- apps/esmtool/esmtool.cpp | 5 ++++- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwworld/cells.cpp | 3 ++- apps/openmw/mwworld/cells.hpp | 5 +++-- apps/openmw/mwworld/cellstore.cpp | 34 +++++++++++++++---------------- apps/openmw/mwworld/cellstore.hpp | 10 ++++----- apps/openmw/mwworld/worldimp.cpp | 24 ++++++++++++++-------- apps/openmw/mwworld/worldimp.hpp | 4 ++-- components/esm/esmcommon.hpp | 4 ++++ components/esm/esmreader.hpp | 2 +- components/esm/loadcell.cpp | 31 +++++++++++++++++++++------- components/esm/loadcell.hpp | 2 +- components/esm_store/reclists.hpp | 19 +++++++++++++++-- 13 files changed, 95 insertions(+), 50 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 4f6d9dbfc..25c4f3a7a 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -220,7 +220,10 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) bool save = (info.mode == "clone"); // Skip back to the beginning of the reference list - cell.restore(esm); + // FIXME: Changes to the references backend required to support multiple plugins have + // almost certainly broken this following line. I'll leave it as is for now, so that + // the compiler does not complain. + cell.restore(esm, 0); // Loop through all the references ESM::CellRef ref; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6710fc68b..06c3002c7 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -106,7 +106,7 @@ namespace MWBase virtual const ESMS::ESMStore& getStore() const = 0; - virtual ESM::ESMReader& getEsmReader() = 0; + virtual std::vector& getEsmReader() = 0; virtual MWWorld::LocalScripts& getLocalScripts() = 0; diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index e5a38d4be..e49835f41 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -85,7 +85,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS return ptr; } -MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader) +MWWorld::Cells::Cells (const ESMS::ESMStore& store, std::vector& reader) : mStore (store), mReader (reader), mIdCache (20, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable mIdCacheIndex (0) @@ -120,6 +120,7 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) if (result->second.mState!=Ptr::CellStore::State_Loaded) { + // Multiple plugin support for landscape data is much easier than for references. The last plugin wins. result->second.load (mStore, mReader); fillContainers (result->second); } diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 3e1383166..3941399f8 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -2,6 +2,7 @@ #define GAME_MWWORLD_CELLS_H #include +#include #include #include "ptr.hpp" @@ -22,7 +23,7 @@ namespace MWWorld class Cells { const ESMS::ESMStore& mStore; - ESM::ESMReader& mReader; + std::vector& mReader; std::map mInteriors; std::map, CellStore> mExteriors; std::vector > mIdCache; @@ -39,7 +40,7 @@ namespace MWWorld public: - Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader); + Cells (const ESMS::ESMStore& store, std::vector& reader); ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole /// world diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 322b43a00..91c0afe26 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -16,7 +16,7 @@ namespace MWWorld mWaterLevel = cell->mWater; } - void CellStore::load (const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::load (const ESMS::ESMStore &store, std::vector &esm) { if (mState!=State_Loaded) { @@ -31,7 +31,7 @@ namespace MWWorld } } - void CellStore::preload (const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::preload (const ESMS::ESMStore &store, std::vector &esm) { if (mState==State_Unloaded) { @@ -41,7 +41,7 @@ namespace MWWorld } } - void CellStore::listRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::listRefs(const ESMS::ESMStore &store, std::vector &esm) { assert (cell); @@ -49,26 +49,24 @@ namespace MWWorld return; // this is a dynamically generated cell -> skipping. // Load references from all plugins that do something with this cell. - // HACK: only use first entry for now, full support requires some more work - //for (int i = 0; i < cell->mContextList.size(); i++) - for (int i = 0; i < 1; i++) + for (size_t i = 0; i < cell->mContextList.size(); i++) { // Reopen the ESM reader and seek to the right position. - // TODO: we will need to intoduce separate "esm"s, one per plugin! - cell->restore (esm); + int index = cell->mContextList.at(i).index; + cell->restore (esm[index], i); ESM::CellRef ref; // Get each reference in turn - while (cell->getNextRef (esm, ref)) + while (cell->getNextRef (esm[index], ref)) { std::string lowerCase; std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: support deletion / moving references out of the cell. no simple "push_back", - // but see what the plugin wants to do. + // TODO: Fully support deletion / moving references out of the cell. no simple "push_back", + // but make sure that the reference exists only once. mIds.push_back (lowerCase); } } @@ -76,7 +74,7 @@ namespace MWWorld std::sort (mIds.begin(), mIds.end()); } - void CellStore::loadRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm) + void CellStore::loadRefs(const ESMS::ESMStore &store, std::vector &esm) { assert (cell); @@ -84,24 +82,24 @@ namespace MWWorld return; // this is a dynamically generated cell -> skipping. // Load references from all plugins that do something with this cell. - // HACK: only use first entry for now, full support requires some more work - //for (int i = 0; i < cell->mContextList.size(); i++) - for (int i = 0; i < 1; i++) + for (size_t i = 0; i < cell->mContextList.size(); i++) { // Reopen the ESM reader and seek to the right position. - // TODO: we will need to intoduce separate "esm"s, one per plugin! - cell->restore(esm); + int index = cell->mContextList.at(i).index; + cell->restore (esm[index], i); ESM::CellRef ref; // Get each reference in turn - while(cell->getNextRef(esm, ref)) + while(cell->getNextRef(esm[index], ref)) { std::string lowerCase; std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); + // TODO: Fully support deletion / moving references out of the cell. No simple loading, + // but make sure that the reference exists only once. Current code clones references. int rec = store.find(ref.mRefID); ref.mRefID = lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index fd739b565..69c4cf9b4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include "refdata.hpp" @@ -126,9 +126,9 @@ namespace MWWorld CellRefList statics; CellRefList weapons; - void load (const ESMS::ESMStore &store, ESM::ESMReader &esm); + void load (const ESMS::ESMStore &store, std::vector &esm); - void preload (const ESMS::ESMStore &store, ESM::ESMReader &esm); + void preload (const ESMS::ESMStore &store, std::vector &esm); /// Call functor (ref) for each reference. functor must return a bool. Returning /// false will abort the iteration. @@ -187,9 +187,9 @@ namespace MWWorld } /// Run through references and store IDs - void listRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm); + void listRefs(const ESMS::ESMStore &store, std::vector &esm); - void loadRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm); + void loadRefs(const ESMS::ESMStore &store, std::vector &esm); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6cf831b53..bbc44f5e1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -179,6 +179,8 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering); int idx = 0; + // NOTE: We might need to reserve one more for the running game / save. + mEsm.resize(master.size() + plugins.size()); for (std::vector::size_type i = 0; i < master.size(); i++, idx++) { boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); @@ -186,10 +188,12 @@ namespace MWWorld std::cout << "Loading ESM " << masterPath.string() << "\n"; // This parses the ESM file - mEsm.setEncoding(encoding); - mEsm.open (masterPath.string()); - mEsm.setIndex(idx); - mStore.load (mEsm); + ESM::ESMReader lEsm; + lEsm.setEncoding(encoding); + lEsm.open (masterPath.string()); + lEsm.setIndex(idx); + mEsm[idx] = lEsm; + mStore.load (mEsm[idx]); } for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) @@ -199,10 +203,12 @@ namespace MWWorld std::cout << "Loading ESP " << pluginPath.string() << "\n"; // This parses the ESP file - mEsm.setEncoding(encoding); - mEsm.open (pluginPath.string()); - mEsm.setIndex(idx); - mStore.load (mEsm); + ESM::ESMReader lEsm; + lEsm.setEncoding(encoding); + lEsm.open (pluginPath.string()); + lEsm.setIndex(idx); + mEsm[idx] = lEsm; + mStore.load (mEsm[idx]); } mPlayer = new MWWorld::Player (mStore.npcs.find ("player"), *this); @@ -282,7 +288,7 @@ namespace MWWorld return mStore; } - ESM::ESMReader& World::getEsmReader() + std::vector& World::getEsmReader() { return mEsm; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c8c56f130..ffb2137c7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -55,7 +55,7 @@ namespace MWWorld MWWorld::Scene *mWorldScene; MWWorld::Player *mPlayer; - ESM::ESMReader mEsm; + std::vector mEsm; ESMS::ESMStore mStore; LocalScripts mLocalScripts; MWWorld::Globals *mGlobalVariables; @@ -127,7 +127,7 @@ namespace MWWorld virtual const ESMS::ESMStore& getStore() const; - virtual ESM::ESMReader& getEsmReader(); + virtual std::vector& getEsmReader(); virtual LocalScripts& getLocalScripts(); diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index e0c5c08af..d61564c67 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -113,6 +113,10 @@ struct ESM_Context size_t leftFile; NAME recName, subName; HEDRstruct header; + // When working with multiple esX files, we will generate lists of all files that + // actually contribute to a specific cell. Therefore, we need to store the index + // of the file belonging to this contest. See CellStore::(list/load)refs for details. + int index; // True if subName has been read but not used. bool subCached; diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 96b164d5e..f09442a57 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -81,7 +81,7 @@ public: // to the individual load() methods. This hack allows to pass this reference // indirectly to the load() method. int idx; - void setIndex(const int index) {idx = index;} + void setIndex(const int index) {idx = index; mCtx.index = index;} const int getIndex() {return idx;} /************************************************************************* diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 65c9c23e7..beedd3cac 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -113,6 +113,8 @@ void Cell::load(ESMReader &esm) // Save position of the cell references and move on mContextList.push_back(esm.getContext()); + if (mContextList.size() > 1) + std::cout << "found two plugins" << std::endl; esm.skipRecord(); } @@ -147,10 +149,9 @@ void Cell::save(ESMWriter &esm) esm.writeHNT("NAM0", mNAM0); } -void Cell::restore(ESMReader &esm) const +void Cell::restore(ESMReader &esm, int iCtx) const { - // TODO: support all contexts in the list! - esm.restoreContext(mContextList[0]); + esm.restoreContext(mContextList[iCtx]); } std::string Cell::getDescription() const @@ -169,15 +170,28 @@ std::string Cell::getDescription() const bool Cell::getNextRef(ESMReader &esm, CellRef &ref) { - // TODO: Add support for moved references. References moved without crossing a cell boundary simply - // overwrite old data. References moved across cell boundaries are using a different set of keywords, - // and I'll have to think more about how this can be done. // TODO: Add support for multiple plugins. This requires a tricky renaming scheme for "ref.mRefnum". // I'll probably add something to "ESMReader", we will need one per plugin anyway. // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; - + + if (esm.isNextSub("MVRF")) { + // Moved existing reference across cell boundaries, so interpret the blocks correctly. + // FIXME: Right now, we don't do anything with this data. This might result in weird behaviour, + // where a moved reference does not appear because the owning cell (i.e. this cell) is not + // loaded in memory. + int movedRefnum = 0; + int destCell[2]; + esm.getHT(movedRefnum); + esm.getHNT(destCell, "CNDT"); + // TODO: Figure out what happens when a reference has moved into an interior cell. This might + // be required for NPCs following the player. + } + // If we have just parsed a MVRF entry, there should be a regular FRMR entry following right there. + // With the exception that this bock technically belongs to a different cell than this one. + // TODO: Figure out a way to handle these weird references that do not belong to this cell. + // This may require some not-so-small behing-the-scenes updates. esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); @@ -228,6 +242,9 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. + // Update: Well, maybe not completely useless. This might actually be + // number_of_references + number_of_references_moved_here_Across_boundaries, + // and could be helpful for collecting these weird moved references. ref.mNam0 = 0; if (esm.isNextSub("NAM0")) { diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 9511ae0e7..ccfdcadd8 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -152,7 +152,7 @@ struct Cell // somewhere other than the file system, you need to pre-open the // ESMReader, and the filename must match the stored filename // exactly. - void restore(ESMReader &esm) const; + void restore(ESMReader &esm, int iCtx) const; std::string getDescription() const; ///< Return a short string describing the cell (mostly used for debugging/logging purpose) diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index eac1b5b72..44b7e6569 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -496,6 +496,11 @@ namespace ESMS { count++; + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded! So first, proceed as usual. + // All cells have a name record, even nameless exterior cells. ESM::Cell *cell = new ESM::Cell; cell->mName = id; @@ -505,12 +510,22 @@ namespace ESMS if(cell->mData.mFlags & ESM::Cell::Interior) { - // Store interior cell by name + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(searchInt(id)); + if (oldcell) { + cell->mContextList.push_back(oldcell->mContextList.at(0)); + delete oldcell; + } intCells[id] = cell; } else { - // Store exterior cells by grid position + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(searchExt(cell->getGridX(), cell->getGridY())); + if (oldcell) { + cell->mContextList.push_back(oldcell->mContextList.at(0)); + delete oldcell; + } extCells[std::make_pair (cell->mData.mX, cell->mData.mY)] = cell; } } From 2175f13b67e9075455bc944b0e32cdd0cb9b5ceb Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 17 Nov 2012 00:21:51 +0100 Subject: [PATCH 006/916] - Add tracking for dependencies between plugins. - Add reference number mangling required for moving references around. --- apps/openmw/mwworld/worldimp.cpp | 6 ++++-- components/esm/esmcommon.hpp | 1 + components/esm/esmreader.cpp | 25 +++++++++++++++++++++++++ components/esm/esmreader.hpp | 3 +++ components/esm/loadcell.cpp | 22 ++++++++++++++++++++-- 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bbc44f5e1..3e23679b1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -190,8 +190,9 @@ namespace MWWorld // This parses the ESM file ESM::ESMReader lEsm; lEsm.setEncoding(encoding); - lEsm.open (masterPath.string()); lEsm.setIndex(idx); + lEsm.setGlobalReaderList(&mEsm); + lEsm.open (masterPath.string()); mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } @@ -205,8 +206,9 @@ namespace MWWorld // This parses the ESP file ESM::ESMReader lEsm; lEsm.setEncoding(encoding); - lEsm.open (pluginPath.string()); lEsm.setIndex(idx); + lEsm.setGlobalReaderList(&mEsm); + lEsm.open (pluginPath.string()); mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index d61564c67..335d12337 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -89,6 +89,7 @@ struct MasterData { std::string name; uint64_t size; + int index; // Position of the parent file in the global list of loaded files }; // Data that is only present in save game files diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 2915a1ce7..d1703a2ac 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -1,5 +1,6 @@ #include "esmreader.hpp" #include +#include namespace ESM { @@ -61,6 +62,7 @@ void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) { openRaw(_esm, name); + std::string fname = boost::filesystem::path(name).filename().string(); if (getRecName() != "TES3") fail("Not a valid Morrowind file"); @@ -78,6 +80,29 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) MasterData m; m.name = getHString(); m.size = getHNLong("DATA"); + // Cache parent esX files by tracking their indices in the global list of + // all files/readers used by the engine. This will greaty help to accelerate + // parsing of reference IDs. + size_t index = ~0; + // TODO: check for case mismatch, it might be required on Windows. + size_t i = 0; + // FIXME: This is ugly! Make it nicer! + for (; i < idx; i++) { + const std::string &candidate = mGlobalReaderList->at(i).getContext().filename; + std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); + if (m.name == fnamecandidate) { + index = i; + break; + } + } + if (index == (size_t)~0) { + // Tried to load a parent file that has not been loaded yet. This is bad, + // the launcher should have taken care of this. + std::string fstring = "File " + fname + " asks for parent file " + m.name + + ", but it has not been loaded yet. Please check your load order."; + fail(fstring); + } + m.index = index; mMasters.push_back(m); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index f09442a57..b415009d3 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -83,6 +83,8 @@ public: int idx; void setIndex(const int index) {idx = index; mCtx.index = index;} const int getIndex() {return idx;} + + void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} /************************************************************************* * @@ -254,6 +256,7 @@ private: SaveData mSaveData; MasterList mMasters; + std::vector *mGlobalReaderList; ToUTF8::FromType mEncoding; }; } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index beedd3cac..1a1811a90 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -170,8 +170,6 @@ std::string Cell::getDescription() const bool Cell::getNextRef(ESMReader &esm, CellRef &ref) { - // TODO: Add support for multiple plugins. This requires a tricky renaming scheme for "ref.mRefnum". - // I'll probably add something to "ESMReader", we will need one per plugin anyway. // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; @@ -194,6 +192,26 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // This may require some not-so-small behing-the-scenes updates. esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); + + // Identify references belonging to a parent file and adapt the ID accordingly. + int local = (ref.mRefnum & 0xff000000) >> 24; + size_t global = esm.getIndex() + 1; + if (local) + { + // If the most significant 8 bits are used, then this reference already exists. + // In this case, do not spawn a new reference, but overwrite the old one. + ref.mRefnum &= 0x00ffffff; // delete old plugin ID + const ESM::ESMReader::MasterList &masters = esm.getMasters(); + // TODO: Test how Morrowind does it! Maybe the first entry in the list should be "1"... + global = masters[local-1].index + 1; + ref.mRefnum |= global << 24; // insert global plugin ID + std::cout << "Refnum_old = " << ref.mRefnum << " " << local << " " << global << std::endl; + } + else + { + // This is an addition by the present plugin. Set the corresponding plugin index. + ref.mRefnum |= global << 24; // insert global plugin ID + } // getHNOT will not change the existing value if the subrecord is // missing From 31fb715bd7be529689e66fb9a33fb5c51b105d3d Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 17 Nov 2012 21:50:25 +0100 Subject: [PATCH 007/916] - Add support for moving existing references by plugin files. No cell changing yet. - Change CellRefList::list from list<> to map so we can identify live references by their Refnumber. - Introduce ContainerRefList, a clone of the original CellRefList. It is now used for containers, which do not track Refnumbers. - Many small tweaks so that the new CellRefList does not conflict with existing code. --- apps/openmw/mwworld/cells.cpp | 12 ++--- apps/openmw/mwworld/cellstore.cpp | 6 +-- apps/openmw/mwworld/cellstore.hpp | 47 +++++++++++++++-- apps/openmw/mwworld/containerstore.cpp | 28 +++++----- apps/openmw/mwworld/containerstore.hpp | 72 +++++++++++++------------- apps/openmw/mwworld/localscripts.cpp | 4 +- apps/openmw/mwworld/scene.cpp | 6 +-- apps/openmw/mwworld/worldimp.cpp | 18 +++---- components/esm/loadcell.cpp | 6 +-- components/esm_store/reclists.hpp | 5 +- 10 files changed, 119 insertions(+), 85 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index e49835f41..667f2d4ca 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -43,30 +43,30 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) cellStore.containers.list.begin()); iter!=cellStore.containers.list.end(); ++iter) { - Ptr container (&*iter, &cellStore); + Ptr container (&iter->second, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->second.base->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.creatures.list.begin()); iter!=cellStore.creatures.list.end(); ++iter) { - Ptr container (&*iter, &cellStore); + Ptr container (&iter->second, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->second.base->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.npcs.list.begin()); iter!=cellStore.npcs.list.end(); ++iter) { - Ptr container (&*iter, &cellStore); + Ptr container (&iter->second, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->base->mInventory, mStore); + iter->second.base->mInventory, mStore); } } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 91c0afe26..0af886124 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -65,8 +65,7 @@ namespace MWWorld std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: Fully support deletion / moving references out of the cell. no simple "push_back", - // but make sure that the reference exists only once. + // TODO: Fully support deletion of references. mIds.push_back (lowerCase); } } @@ -98,8 +97,7 @@ namespace MWWorld std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: Fully support deletion / moving references out of the cell. No simple loading, - // but make sure that the reference exists only once. Current code clones references. + // TODO: Fully support deletion of references. int rec = store.find(ref.mRefID); ref.mRefID = lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 69c4cf9b4..236f67231 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -47,6 +47,47 @@ namespace MWWorld /// A list of cell references template struct CellRefList + { + typedef LiveCellRef LiveRef; + typedef std::map List; + List list; + + // Search for the given reference in the given reclist from + // ESMStore. Insert the reference into the list if a match is + // found. If not, throw an exception. + template + void find(ESM::CellRef &ref, const Y& recList) + { + const X* obj = recList.find(ref.mRefID); + if(obj == NULL) + throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + + list[ref.mRefnum] = LiveRef(ref, obj); + } + + LiveRef *find (const std::string& name) + { + for (typename std::map::iterator iter (list.begin()); iter!=list.end(); ++iter) + { + if (iter->second.mData.getCount() > 0 && iter->second.ref.mRefID == name) + return &iter->second; + } + + return 0; + } + + LiveRef &insert(const LiveRef &item) { + list[item.ref.mRefnum] = item; + return list[item.ref.mRefnum]; + } + }; + + /// A list of container references. These references do not track their mRefnumber. + /// Otherwise, taking 1 of 20 instances of an object would produce multiple objects + /// with the same reference. + // TODO: Check how Morrowind does this! Maybe auto-generate references on drop. + template + struct ContainerRefList { typedef LiveCellRef LiveRef; typedef std::list List; @@ -62,10 +103,6 @@ namespace MWWorld if(obj == NULL) throw std::runtime_error("Error resolving cell reference " + ref.mRefID); - // TODO: this line must be modified for multiple plugins and moved references. - // This means: no simple "push back", but search for an existing reference with - // this ID first! If it exists, merge data into this list instead of just adding it. - // I'll probably generate a separate method jist for this. list.push_back(LiveRef(ref, obj)); } @@ -180,7 +217,7 @@ namespace MWWorld { for (typename List::List::iterator iter (list.list.begin()); iter!=list.list.end(); ++iter) - if (!functor (iter->ref, iter->mData)) + if (!functor (iter->second.ref, iter->second.mData)) return false; return true; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5c4dd03a4..035f79310 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -19,11 +19,11 @@ namespace { template - float getTotalWeight (const MWWorld::CellRefList& cellRefList) + float getTotalWeight (const MWWorld::ContainerRefList& cellRefList) { float sum = 0; - for (typename MWWorld::CellRefList::List::const_iterator iter ( + for (typename MWWorld::ContainerRefList::List::const_iterator iter ( cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) @@ -270,29 +270,29 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor ++*this; } -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Potion), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mPotion(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Apparatus), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mApparatus(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Armor), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mArmor(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Book), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mBook(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Clothing), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mClothing(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Probe), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mProbe(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Repair), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mRepair(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Weapon), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mWeapon(iterator){} void MWWorld::ContainerStoreIterator::incType() diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index ae27fad3d..9611b9c21 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -37,18 +37,18 @@ namespace MWWorld private: - MWWorld::CellRefList potions; - MWWorld::CellRefList appas; - MWWorld::CellRefList armors; - MWWorld::CellRefList books; - MWWorld::CellRefList clothes; - MWWorld::CellRefList ingreds; - MWWorld::CellRefList lights; - MWWorld::CellRefList lockpicks; - MWWorld::CellRefList miscItems; - MWWorld::CellRefList probes; - MWWorld::CellRefList repairs; - MWWorld::CellRefList weapons; + MWWorld::ContainerRefList potions; + MWWorld::ContainerRefList appas; + MWWorld::ContainerRefList armors; + MWWorld::ContainerRefList books; + MWWorld::ContainerRefList clothes; + MWWorld::ContainerRefList ingreds; + MWWorld::ContainerRefList lights; + MWWorld::ContainerRefList lockpicks; + MWWorld::ContainerRefList miscItems; + MWWorld::ContainerRefList probes; + MWWorld::ContainerRefList repairs; + MWWorld::ContainerRefList weapons; int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; @@ -119,18 +119,18 @@ namespace MWWorld ContainerStore *mContainer; mutable Ptr mPtr; - MWWorld::CellRefList::List::iterator mPotion; - MWWorld::CellRefList::List::iterator mApparatus; - MWWorld::CellRefList::List::iterator mArmor; - MWWorld::CellRefList::List::iterator mBook; - MWWorld::CellRefList::List::iterator mClothing; - MWWorld::CellRefList::List::iterator mIngredient; - MWWorld::CellRefList::List::iterator mLight; - MWWorld::CellRefList::List::iterator mLockpick; - MWWorld::CellRefList::List::iterator mMiscellaneous; - MWWorld::CellRefList::List::iterator mProbe; - MWWorld::CellRefList::List::iterator mRepair; - MWWorld::CellRefList::List::iterator mWeapon; + MWWorld::ContainerRefList::List::iterator mPotion; + MWWorld::ContainerRefList::List::iterator mApparatus; + MWWorld::ContainerRefList::List::iterator mArmor; + MWWorld::ContainerRefList::List::iterator mBook; + MWWorld::ContainerRefList::List::iterator mClothing; + MWWorld::ContainerRefList::List::iterator mIngredient; + MWWorld::ContainerRefList::List::iterator mLight; + MWWorld::ContainerRefList::List::iterator mLockpick; + MWWorld::ContainerRefList::List::iterator mMiscellaneous; + MWWorld::ContainerRefList::List::iterator mProbe; + MWWorld::ContainerRefList::List::iterator mRepair; + MWWorld::ContainerRefList::List::iterator mWeapon; private: @@ -141,18 +141,18 @@ namespace MWWorld ///< Begin-iterator // construct iterator using a CellRefList iterator - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); void incType(); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index d0d698feb..1ef1cdeaf 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -15,9 +15,9 @@ namespace cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) { - if (!iter->base->mScript.empty() && iter->mData.getCount()) + if (!iter->second.base->mScript.empty() && iter->second.mData.getCount()) { - localScripts.add (iter->base->mScript, MWWorld::Ptr (&*iter, cell)); + localScripts.add (iter->second.base->mScript, MWWorld::Ptr (&iter->second, cell)); } } } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 881b090fa..b6add7fbf 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -23,7 +23,7 @@ namespace if (!cellRefList.list.empty()) { const MWWorld::Class& class_ = - MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.list.begin(), &cell)); + MWWorld::Class::get (MWWorld::Ptr (&cellRefList.list.begin()->second, &cell)); int numRefs = cellRefList.list.size(); int current = 0; @@ -33,9 +33,9 @@ namespace MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; - if (it->mData.getCount() || it->mData.isEnabled()) + if (it->second.mData.getCount() || it->second.mData.isEnabled()) { - MWWorld::Ptr ptr (&*it, &cell); + MWWorld::Ptr ptr (&it->second, &cell); try { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3e23679b1..e999100f0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -28,13 +28,13 @@ namespace cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) { - if (!iter->base->script.empty() && iter->mData.getCount()) + if (!iter->second->base->script.empty() && iter->second->mData.getCount()) { - if (const ESM::Script *script = store.scripts.find (iter->base->script)) + if (const ESM::Script *script = store.scripts.find (iter->second->base->script)) { iter->mData.setLocals (*script); - localScripts.add (iter->base->script, MWWorld::Ptr (&*iter, cell)); + localScripts.add (iter->base->script, MWWorld::Ptr (&iter->second, cell)); } } } @@ -48,10 +48,10 @@ namespace for (iterator iter (refList.list.begin()); iter!=refList.list.end(); ++iter) { - if(iter->mData.getCount() > 0 && iter->mData.getBaseNode()){ - if (iter->mData.getHandle()==handle) + if (iter->second.mData.getCount() > 0 && iter->second.mData.getBaseNode()){ + if (iter->second.mData.getHandle()==handle) { - return &*iter; + return &iter->second; } } } @@ -1115,10 +1115,10 @@ namespace MWWorld std::vector result; MWWorld::CellRefList& doors = cell->doors; - std::list< MWWorld::LiveCellRef >& refList = doors.list; - for (std::list< MWWorld::LiveCellRef >::iterator it = refList.begin(); it != refList.end(); ++it) + std::map >& refList = doors.list; + for (std::map >::iterator it = refList.begin(); it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = *it; + MWWorld::LiveCellRef& ref = it->second; if (ref.ref.mTeleport) { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 1a1811a90..b7f27b08d 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -113,8 +113,6 @@ void Cell::load(ESMReader &esm) // Save position of the cell references and move on mContextList.push_back(esm.getContext()); - if (mContextList.size() > 1) - std::cout << "found two plugins" << std::endl; esm.skipRecord(); } @@ -202,10 +200,8 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // In this case, do not spawn a new reference, but overwrite the old one. ref.mRefnum &= 0x00ffffff; // delete old plugin ID const ESM::ESMReader::MasterList &masters = esm.getMasters(); - // TODO: Test how Morrowind does it! Maybe the first entry in the list should be "1"... global = masters[local-1].index + 1; ref.mRefnum |= global << 24; // insert global plugin ID - std::cout << "Refnum_old = " << ref.mRefnum << " " << local << " " << global << std::endl; } else { @@ -256,7 +252,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNOT(ref.mFltv, "FLTV"); esm.getHNT(ref.mPos, "DATA", 24); - + // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 44b7e6569..14452fca9 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -523,7 +523,10 @@ namespace ESMS // Store exterior cells by grid position, try to merge with existing parent data. ESM::Cell *oldcell = const_cast(searchExt(cell->getGridX(), cell->getGridY())); if (oldcell) { - cell->mContextList.push_back(oldcell->mContextList.at(0)); + // The load order is important. Push the new source context on the *back* of the existing list, + // and then move the list to the new cell. + oldcell->mContextList.push_back(cell->mContextList.at(0)); + cell->mContextList = oldcell->mContextList; delete oldcell; } extCells[std::make_pair (cell->mData.mX, cell->mData.mY)] = cell; From c3cd6e8a8aaccf74a8e62d6460a938584be4fc4c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 21 Nov 2012 17:31:18 +0100 Subject: [PATCH 008/916] new attempt at the editor --- CMakeLists.txt | 7 +++- apps/opencs/CMakeLists.txt | 44 +++++++++++++++++++++++ apps/opencs/main.cpp | 5 +++ apps/opencs/model/doc/document.cpp | 4 +++ apps/opencs/model/doc/document.hpp | 17 +++++++++ apps/opencs/model/doc/documentmanager.cpp | 37 +++++++++++++++++++ apps/opencs/model/doc/documentmanager.hpp | 31 ++++++++++++++++ 7 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/CMakeLists.txt create mode 100644 apps/opencs/main.cpp create mode 100644 apps/opencs/model/doc/document.cpp create mode 100644 apps/opencs/model/doc/document.hpp create mode 100644 apps/opencs/model/doc/documentmanager.cpp create mode 100644 apps/opencs/model/doc/documentmanager.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 78388e20f..d657de6ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) +option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF) @@ -244,7 +245,7 @@ if (APPLE) else () set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) endif () - + #set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/") configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist @@ -462,6 +463,10 @@ if (BUILD_MWINIIMPORTER) add_subdirectory( apps/mwiniimporter ) endif() +if (BUILD_OPENCS) + add_subdirectory (apps/opencs) +endif() + # UnitTests if (BUILD_UNITTESTS) add_subdirectory( apps/openmw_test_suite ) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt new file mode 100644 index 000000000..d213f68f9 --- /dev/null +++ b/apps/opencs/CMakeLists.txt @@ -0,0 +1,44 @@ + +set (OPENCS_SRC + main.cpp + + model/doc/documentmanager.cpp model/doc/document.cpp + ) + +set (OPENCS_HDR + model/doc/documentmanager.hpp model/doc/document.hpp + ) + +set (OPENCS_US + ) + +set (OPENCS_RES + ) + +source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) + +if(WIN32) + set(QT_USE_QTMAIN TRUE) +endif(WIN32) + +find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED) +include(${QT_USE_FILE}) + +qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) +qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR}) +qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +add_executable(opencs + ${OPENCS_SRC} + ${OPENCS_UI_HDR} + ${OPENCS_MOC_SRC} + ${OPENCS_RES_SRC} +) + +target_link_libraries(opencs + ${Boost_LIBRARIES} + ${QT_LIBRARIES} + components +) \ No newline at end of file diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp new file mode 100644 index 000000000..cd443603b --- /dev/null +++ b/apps/opencs/main.cpp @@ -0,0 +1,5 @@ + +int main(int argc, char *argv[]) +{ + +} \ No newline at end of file diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp new file mode 100644 index 000000000..7154c484b --- /dev/null +++ b/apps/opencs/model/doc/document.cpp @@ -0,0 +1,4 @@ + +#include "document.hpp" + +CSMDoc::Document::Document() {} \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp new file mode 100644 index 000000000..7badf8fd7 --- /dev/null +++ b/apps/opencs/model/doc/document.hpp @@ -0,0 +1,17 @@ +#ifndef CSM_DOCUMENT_H +#define CSM_DOCUMENT_H + +namespace CSMDoc +{ + class Document + { + Document (const Document&); + Document& operator= (const Document&); + + public: + + Document(); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp new file mode 100644 index 000000000..68595f2d4 --- /dev/null +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -0,0 +1,37 @@ + +#include "documentmanager.hpp" + +#include +#include + +#include "document.hpp" + +CSMDoc::DocumentManager::DocumentManager() {} + +CSMDoc::DocumentManager::~DocumentManager() +{ + for (std::vector::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter) + delete *iter; +} + +CSMDoc::Document *CSMDoc::DocumentManager::addDocument() +{ + Document *document = new Document; + + mDocuments.push_back (document); + + return document; +} + +bool CSMDoc::DocumentManager::removeDocument (Document *document) +{ + std::vector::iterator iter = std::find (mDocuments.begin(), mDocuments.end(), document); + + if (iter==mDocuments.end()) + throw std::runtime_error ("removing invalid document"); + + mDocuments.erase (iter); + delete document; + + return mDocuments.empty(); +} \ No newline at end of file diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp new file mode 100644 index 000000000..7f0d388bc --- /dev/null +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -0,0 +1,31 @@ +#ifndef CSM_DOCUMENTMGR_H +#define CSM_DOCUMENTMGR_H + +#include + +namespace CSMDoc +{ + class Document; + + class DocumentManager + { + std::vector mDocuments; + + DocumentManager (const DocumentManager&); + DocumentManager& operator= (const DocumentManager&); + + public: + + DocumentManager(); + + ~DocumentManager(); + + Document *addDocument(); + ///< The ownership of the returned document is not transferred to the caller. + + bool removeDocument (Document *document); + ///< \return last document removed? + }; +} + +#endif \ No newline at end of file From 9834bb3ad52db108a11d6afe1a26d31f6833d925 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Nov 2012 13:30:02 +0100 Subject: [PATCH 009/916] basic document handling --- apps/opencs/CMakeLists.txt | 8 ++++- apps/opencs/editor.cpp | 21 +++++++++++++ apps/opencs/editor.hpp | 29 +++++++++++++++++ apps/opencs/main.cpp | 8 +++++ apps/opencs/model/doc/document.hpp | 5 +-- apps/opencs/model/doc/documentmanager.hpp | 4 +-- apps/opencs/view/doc/view.cpp | 8 +++++ apps/opencs/view/doc/view.hpp | 30 ++++++++++++++++++ apps/opencs/view/doc/viewmanager.cpp | 26 ++++++++++++++++ apps/opencs/view/doc/viewmanager.hpp | 38 +++++++++++++++++++++++ 10 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 apps/opencs/editor.cpp create mode 100644 apps/opencs/editor.hpp create mode 100644 apps/opencs/view/doc/view.cpp create mode 100644 apps/opencs/view/doc/view.hpp create mode 100644 apps/opencs/view/doc/viewmanager.cpp create mode 100644 apps/opencs/view/doc/viewmanager.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d213f68f9..d7f113447 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -1,12 +1,18 @@ set (OPENCS_SRC - main.cpp + main.cpp editor.cpp model/doc/documentmanager.cpp model/doc/document.cpp + + view/doc/viewmanager.cpp view/doc/view.cpp ) set (OPENCS_HDR + editor.hpp + model/doc/documentmanager.hpp model/doc/document.hpp + + view/doc/viewmanager.hpp view/doc/view.hpp ) set (OPENCS_US diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp new file mode 100644 index 000000000..0a8a137f6 --- /dev/null +++ b/apps/opencs/editor.cpp @@ -0,0 +1,21 @@ + +#include "editor.hpp" + +#include + +CS::Editor::Editor() +{ +} + +void CS::Editor::createDocument() +{ + CSMDoc::Document *document = mDocumentManager.addDocument(); + mViewManager.addView (document); +} + +int CS::Editor::run() +{ + createDocument(); + + return QApplication::exec(); +} \ No newline at end of file diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp new file mode 100644 index 000000000..6e183b843 --- /dev/null +++ b/apps/opencs/editor.hpp @@ -0,0 +1,29 @@ +#ifndef CS_EDITOR_H +#define CS_EDITOR_H + +#include "model/doc/documentmanager.hpp" +#include "view/doc/viewmanager.hpp" + +namespace CS +{ + class Editor + { + CSMDoc::DocumentManager mDocumentManager; + CSVDoc::ViewManager mViewManager; + + // not implemented + Editor (const Editor&); + Editor& operator= (const Editor&); + + public: + + Editor(); + + void createDocument(); + + int run(); + ///< \return error status + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index cd443603b..15772eba0 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -1,5 +1,13 @@ +#include "editor.hpp" + +#include + int main(int argc, char *argv[]) { + QApplication mApplication (argc, argv); + CS::Editor editor; + + return editor.run(); } \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 7badf8fd7..e44085962 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -1,10 +1,11 @@ -#ifndef CSM_DOCUMENT_H -#define CSM_DOCUMENT_H +#ifndef CSM_DOC_DOCUMENT_H +#define CSM_DOC_DOCUMENT_H namespace CSMDoc { class Document { + // not implemented Document (const Document&); Document& operator= (const Document&); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 7f0d388bc..f20f3101d 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -1,5 +1,5 @@ -#ifndef CSM_DOCUMENTMGR_H -#define CSM_DOCUMENTMGR_H +#ifndef CSM_DOC_DOCUMENTMGR_H +#define CSM_DOC_DOCUMENTMGR_H #include diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp new file mode 100644 index 000000000..2bad69bad --- /dev/null +++ b/apps/opencs/view/doc/view.cpp @@ -0,0 +1,8 @@ + +#include "view.hpp" + +CSVDoc::View::View (CSMDoc::Document *document) : mDocument (document) +{ + resize (200, 200); + setWindowTitle ("New Document"); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp new file mode 100644 index 000000000..797eef083 --- /dev/null +++ b/apps/opencs/view/doc/view.hpp @@ -0,0 +1,30 @@ +#ifndef CSV_DOC_VIEW_H +#define CSV_DOC_VIEW_H + +#include + +namespace CSMDoc +{ + class Document; +} + +namespace CSVDoc +{ + class View : public QWidget + { + Q_OBJECT + + CSMDoc::Document *mDocument; + + // not implemented + View (const View&); + View& operator= (const View&); + + public: + + View (CSMDoc::Document *document); + ///< The ownership of \a document is not transferred to *this. + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp new file mode 100644 index 000000000..59b79be47 --- /dev/null +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -0,0 +1,26 @@ + +#include "viewmanager.hpp" + +#include "view.hpp" + +CSVDoc::ViewManager::ViewManager() +{ + +} + +CSVDoc::ViewManager::~ViewManager() +{ + for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + delete *iter; +} + +CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) +{ + View *view = new View (document); + + mViews.push_back (view); + + view->show(); + + return view; +} \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp new file mode 100644 index 000000000..dc6a07bce --- /dev/null +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -0,0 +1,38 @@ +#ifndef CSV_DOC_VIEWMANAGER_H +#define CSV_DOC_VIEWMANAGER_H + +#include + +namespace CSMDoc +{ + class Document; +} + +namespace CSVDoc +{ + class View; + + class ViewManager + { + std::vector mViews; + + // not implemented + ViewManager (const ViewManager&); + ViewManager& operator= (const ViewManager&); + + public: + + ViewManager(); + + ~ViewManager(); + + View *addView (CSMDoc::Document *document); + ///< The ownership of the returned view is not transferred. + + + + }; + +} + +#endif \ No newline at end of file From 758371d7e4c346f92b715bb3cb26ec9dfbd58e55 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Nov 2012 14:10:23 +0100 Subject: [PATCH 010/916] implemented view/document closing --- apps/opencs/editor.cpp | 2 +- apps/opencs/view/doc/view.cpp | 25 ++++++++++++++++- apps/opencs/view/doc/view.hpp | 13 ++++++++- apps/opencs/view/doc/viewmanager.cpp | 41 ++++++++++++++++++++++++++-- apps/opencs/view/doc/viewmanager.hpp | 10 ++++++- 5 files changed, 85 insertions(+), 6 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 0a8a137f6..264ae7543 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -3,7 +3,7 @@ #include -CS::Editor::Editor() +CS::Editor::Editor() : mViewManager (mDocumentManager) { } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 2bad69bad..51078d448 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -1,8 +1,31 @@ #include "view.hpp" -CSVDoc::View::View (CSMDoc::Document *document) : mDocument (document) +#include + +#include + +#include "viewmanager.hpp" + +void CSVDoc::View::closeEvent (QCloseEvent *event) +{ + if (!mViewManager.closeRequest (this)) + event->ignore(); +} + +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document) +: mViewManager (viewManager), mDocument (document) { resize (200, 200); setWindowTitle ("New Document"); +} + +const CSMDoc::Document *CSVDoc::View::getDocument() const +{ + return mDocument; +} + +CSMDoc::Document *CSVDoc::View::getDocument() +{ + return mDocument; } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 797eef083..b12bb7e41 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -10,20 +10,31 @@ namespace CSMDoc namespace CSVDoc { + class ViewManager; + class View : public QWidget { Q_OBJECT + ViewManager& mViewManager; CSMDoc::Document *mDocument; // not implemented View (const View&); View& operator= (const View&); + private: + + void closeEvent (QCloseEvent *event); + public: - View (CSMDoc::Document *document); + View (ViewManager& viewManager, CSMDoc::Document *document); ///< The ownership of \a document is not transferred to *this. + + const CSMDoc::Document *getDocument() const; + + CSMDoc::Document *getDocument(); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 59b79be47..da73213f7 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -1,9 +1,12 @@ #include "viewmanager.hpp" +#include "../../model/doc/documentmanager.hpp" + #include "view.hpp" -CSVDoc::ViewManager::ViewManager() +CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) +: mDocumentManager (documentManager) { } @@ -12,15 +15,49 @@ CSVDoc::ViewManager::~ViewManager() { for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; + + for (std::vector::iterator iter (mClosed.begin()); iter!=mClosed.end(); ++iter) + delete *iter; } CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) { - View *view = new View (document); + View *view = new View (*this, document); mViews.push_back (view); view->show(); return view; +} + +int CSVDoc::ViewManager::countViews (const CSMDoc::Document *document) const +{ + int count = 0; + + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + if ((*iter)->getDocument()==document) + ++count; + + return count; +} + +bool CSVDoc::ViewManager::closeRequest (View *view) +{ + std::vector::iterator iter = std::find (mViews.begin(), mViews.end(), view); + + if (iter!=mViews.end()) + { + bool last = countViews (view->getDocument())<=1; + + /// \todo check if document has not been saved -> return false and start close dialogue + + mViews.erase (iter); + mClosed.push_back (view); + + if (last) + mDocumentManager.removeDocument (view->getDocument()); + } + + return true; } \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index dc6a07bce..6901590ed 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -6,6 +6,7 @@ namespace CSMDoc { class Document; + class DocumentManager; } namespace CSVDoc @@ -14,7 +15,9 @@ namespace CSVDoc class ViewManager { + CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; + std::vector mClosed; // not implemented ViewManager (const ViewManager&); @@ -22,13 +25,18 @@ namespace CSVDoc public: - ViewManager(); + ViewManager (CSMDoc::DocumentManager& documentManager); ~ViewManager(); View *addView (CSMDoc::Document *document); ///< The ownership of the returned view is not transferred. + int countViews (const CSMDoc::Document *document) const; + ///< Return number of views for \a document. + + bool closeRequest (View *view); + }; From 789cecb9df5616fd49717ec006b3c7962a73b408 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Nov 2012 14:49:58 +0100 Subject: [PATCH 011/916] added main menu and implemented new view function --- apps/opencs/view/doc/view.cpp | 20 ++++++++++++++++++++ apps/opencs/view/doc/view.hpp | 12 ++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 51078d448..847462964 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "viewmanager.hpp" @@ -13,11 +14,25 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) event->ignore(); } +void CSVDoc::View::setupUi() +{ + // window menu + QMenu *view = menuBar()->addMenu (tr ("&View")); + + QAction *newWindow = new QAction (tr ("&New View"), this); + connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); + + view->addAction (newWindow); +} + CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document) : mViewManager (viewManager), mDocument (document) { + setCentralWidget (new QWidget); resize (200, 200); setWindowTitle ("New Document"); + + setupUi(); } const CSMDoc::Document *CSVDoc::View::getDocument() const @@ -28,4 +43,9 @@ const CSMDoc::Document *CSVDoc::View::getDocument() const CSMDoc::Document *CSVDoc::View::getDocument() { return mDocument; +} + +void CSVDoc::View::newView() +{ + mViewManager.addView (mDocument); } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index b12bb7e41..df88ff2cc 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -1,7 +1,9 @@ #ifndef CSV_DOC_VIEW_H #define CSV_DOC_VIEW_H -#include +#include + +class QAction; namespace CSMDoc { @@ -12,7 +14,7 @@ namespace CSVDoc { class ViewManager; - class View : public QWidget + class View : public QMainWindow { Q_OBJECT @@ -27,6 +29,8 @@ namespace CSVDoc void closeEvent (QCloseEvent *event); + void setupUi(); + public: View (ViewManager& viewManager, CSMDoc::Document *document); @@ -35,6 +39,10 @@ namespace CSVDoc const CSMDoc::Document *getDocument() const; CSMDoc::Document *getDocument(); + + private slots: + + void newView(); }; } From 1ddcea1f072e5cd727f5066c911f0a1015cfd983 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Nov 2012 15:09:04 +0100 Subject: [PATCH 012/916] display view indices in title bar --- apps/opencs/view/doc/view.cpp | 30 +++++++++++++++++++++++----- apps/opencs/view/doc/view.hpp | 8 +++++++- apps/opencs/view/doc/viewmanager.cpp | 26 +++++++++++++++++++++++- apps/opencs/view/doc/viewmanager.hpp | 2 ++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 847462964..406ce7dc7 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -1,7 +1,7 @@ #include "view.hpp" -#include +#include #include #include @@ -16,7 +16,7 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) void CSVDoc::View::setupUi() { - // window menu + // view menu QMenu *view = menuBar()->addMenu (tr ("&View")); QAction *newWindow = new QAction (tr ("&New View"), this); @@ -25,12 +25,25 @@ void CSVDoc::View::setupUi() view->addAction (newWindow); } -CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document) -: mViewManager (viewManager), mDocument (document) +void CSVDoc::View::updateTitle() +{ + std::ostringstream stream; + + stream << "New Document "; + + if (mViewTotal>1) + stream << " [" << (mViewIndex+1) << "/" << mViewTotal << "]"; + + setWindowTitle (stream.str().c_str()); +} + +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) +: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { setCentralWidget (new QWidget); resize (200, 200); - setWindowTitle ("New Document"); + + updateTitle(); setupUi(); } @@ -45,6 +58,13 @@ CSMDoc::Document *CSVDoc::View::getDocument() return mDocument; } +void CSVDoc::View::setIndex (int viewIndex, int totalViews) +{ + mViewIndex = viewIndex; + mViewTotal = totalViews; + updateTitle(); +} + void CSVDoc::View::newView() { mViewManager.addView (mDocument); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index df88ff2cc..78ec45a5d 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -20,6 +20,8 @@ namespace CSVDoc ViewManager& mViewManager; CSMDoc::Document *mDocument; + int mViewIndex; + int mViewTotal; // not implemented View (const View&); @@ -31,15 +33,19 @@ namespace CSVDoc void setupUi(); + void updateTitle(); + public: - View (ViewManager& viewManager, CSMDoc::Document *document); + View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); ///< The ownership of \a document is not transferred to *this. const CSMDoc::Document *getDocument() const; CSMDoc::Document *getDocument(); + void setIndex (int viewIndex, int totalViews); + private slots: void newView(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index da73213f7..f6ac6e43d 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -1,10 +1,30 @@ #include "viewmanager.hpp" +#include + #include "../../model/doc/documentmanager.hpp" #include "view.hpp" +void CSVDoc::ViewManager::updateIndices() +{ + std::map > documents; + + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + { + std::map >::iterator document = documents.find ((*iter)->getDocument()); + + if (document==documents.end()) + document = + documents.insert ( + std::make_pair ((*iter)->getDocument(), std::make_pair (0, countViews ((*iter)->getDocument())))). + first; + + (*iter)->setIndex (document->second.first++, document->second.second); + } +} + CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager) { @@ -22,12 +42,14 @@ CSVDoc::ViewManager::~ViewManager() CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) { - View *view = new View (*this, document); + View *view = new View (*this, document, countViews (document)+1); mViews.push_back (view); view->show(); + updateIndices(); + return view; } @@ -57,6 +79,8 @@ bool CSVDoc::ViewManager::closeRequest (View *view) if (last) mDocumentManager.removeDocument (view->getDocument()); + else + updateIndices(); } return true; diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 6901590ed..765fafbea 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -23,6 +23,8 @@ namespace CSVDoc ViewManager (const ViewManager&); ViewManager& operator= (const ViewManager&); + void updateIndices(); + public: ViewManager (CSMDoc::DocumentManager& documentManager); From ed3d8b8ca2a4cd5dea2870f5bbbcf3f7de6abb0c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Nov 2012 15:54:31 +0100 Subject: [PATCH 013/916] added undo stack and undo/redo actions --- apps/opencs/model/doc/document.cpp | 7 ++++++- apps/opencs/model/doc/document.hpp | 6 ++++++ apps/opencs/view/doc/view.cpp | 25 ++++++++++++++++++++++--- apps/opencs/view/doc/view.hpp | 4 ++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7154c484b..448598a4e 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,4 +1,9 @@ #include "document.hpp" -CSMDoc::Document::Document() {} \ No newline at end of file +CSMDoc::Document::Document() {} + +QUndoStack& CSMDoc::Document::getUndoStack() +{ + return mUndoStack; +} \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index e44085962..1dea7afc2 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -1,10 +1,14 @@ #ifndef CSM_DOC_DOCUMENT_H #define CSM_DOC_DOCUMENT_H +#include + namespace CSMDoc { class Document { + QUndoStack mUndoStack; + // not implemented Document (const Document&); Document& operator= (const Document&); @@ -12,6 +16,8 @@ namespace CSMDoc public: Document(); + + QUndoStack& getUndoStack(); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 406ce7dc7..7a2296fed 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -6,6 +6,8 @@ #include #include +#include "../../model/doc/document.hpp" + #include "viewmanager.hpp" void CSVDoc::View::closeEvent (QCloseEvent *event) @@ -14,17 +16,34 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) event->ignore(); } -void CSVDoc::View::setupUi() +void CSVDoc::View::setupEditMenu() +{ + QMenu *edit = menuBar()->addMenu (tr ("&Edit")); + + QAction *undo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo")); + undo->setShortcuts (QKeySequence::Undo); + edit->addAction (undo); + + QAction *redo = mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); + redo->setShortcuts (QKeySequence::Redo); + edit->addAction (redo); +} + +void CSVDoc::View::setupViewMenu() { - // view menu QMenu *view = menuBar()->addMenu (tr ("&View")); QAction *newWindow = new QAction (tr ("&New View"), this); connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); - view->addAction (newWindow); } +void CSVDoc::View::setupUi() +{ + setupEditMenu(); + setupViewMenu(); +} + void CSVDoc::View::updateTitle() { std::ostringstream stream; diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 78ec45a5d..457cc84fa 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -31,6 +31,10 @@ namespace CSVDoc void closeEvent (QCloseEvent *event); + void setupEditMenu(); + + void setupViewMenu(); + void setupUi(); void updateTitle(); From 8e546ebd30a6fb8c983bf11ccd9ce22f073b31ed Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Nov 2012 16:00:23 +0100 Subject: [PATCH 014/916] added test command --- apps/opencs/view/doc/view.cpp | 10 ++++++++++ apps/opencs/view/doc/view.hpp | 2 ++ 2 files changed, 12 insertions(+) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 7a2296fed..c5792b27a 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -27,6 +27,11 @@ void CSVDoc::View::setupEditMenu() QAction *redo = mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); redo->setShortcuts (QKeySequence::Redo); edit->addAction (redo); + + // test + QAction *test = new QAction (tr ("&Test Command"), this); + connect (test, SIGNAL (triggered()), this, SLOT (test())); + edit->addAction (test); } void CSVDoc::View::setupViewMenu() @@ -87,4 +92,9 @@ void CSVDoc::View::setIndex (int viewIndex, int totalViews) void CSVDoc::View::newView() { mViewManager.addView (mDocument); +} + +void CSVDoc::View::test() +{ + mDocument->getUndoStack().push (new QUndoCommand()); } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 457cc84fa..2c312715a 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -53,6 +53,8 @@ namespace CSVDoc private slots: void newView(); + + void test(); }; } From d7c63d4c74472e7bffd47531319c94343feb646f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 22 Nov 2012 23:42:17 +0100 Subject: [PATCH 015/916] track document modification state and display it in the top level window title bar --- apps/opencs/model/doc/document.cpp | 20 +++++++++++++++++++- apps/opencs/model/doc/document.hpp | 22 +++++++++++++++++++++- apps/opencs/view/doc/view.cpp | 8 ++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/doc/viewmanager.cpp | 15 +++++++++++++++ apps/opencs/view/doc/viewmanager.hpp | 11 ++++++++--- 6 files changed, 73 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 448598a4e..8770b3b90 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,9 +1,27 @@ #include "document.hpp" -CSMDoc::Document::Document() {} +CSMDoc::Document::Document() +{ + connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); +} QUndoStack& CSMDoc::Document::getUndoStack() { return mUndoStack; +} + +int CSMDoc::Document::getState() const +{ + int state = 0; + + if (!mUndoStack.isClean()) + state |= State_Modified; + + return state; +} + +void CSMDoc::Document::modificationStateChanged (bool clean) +{ + emit stateChanged (getState(), this); } \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 1dea7afc2..0499aaf9f 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -2,11 +2,21 @@ #define CSM_DOC_DOCUMENT_H #include +#include namespace CSMDoc { - class Document + class Document : public QObject { + Q_OBJECT + + public: + + enum State + { + State_Modified = 1 + }; + QUndoStack mUndoStack; // not implemented @@ -18,6 +28,16 @@ namespace CSMDoc Document(); QUndoStack& getUndoStack(); + + int getState() const; + + signals: + + void stateChanged (int state, CSMDoc::Document *document); + + private slots: + + void modificationStateChanged (bool clean); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index c5792b27a..be753e216 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -55,6 +55,9 @@ void CSVDoc::View::updateTitle() stream << "New Document "; + if (mDocument->getState() & CSMDoc::Document::State_Modified) + stream << " *"; + if (mViewTotal>1) stream << " [" << (mViewIndex+1) << "/" << mViewTotal << "]"; @@ -89,6 +92,11 @@ void CSVDoc::View::setIndex (int viewIndex, int totalViews) updateTitle(); } +void CSVDoc::View::updateDocumentState() +{ + updateTitle(); +} + void CSVDoc::View::newView() { mViewManager.addView (mDocument); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 2c312715a..67eafe2d5 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -50,6 +50,8 @@ namespace CSVDoc void setIndex (int viewIndex, int totalViews); + void updateDocumentState(); + private slots: void newView(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index f6ac6e43d..ad391dabe 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -4,6 +4,7 @@ #include #include "../../model/doc/documentmanager.hpp" +#include "../../model/doc/document.hpp" #include "view.hpp" @@ -42,6 +43,13 @@ CSVDoc::ViewManager::~ViewManager() CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) { + if (countViews (document)==0) + { + // new document + connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), + this, SLOT (documentStateChanged (int, CSMDoc::Document *))); + } + View *view = new View (*this, document, countViews (document)+1); mViews.push_back (view); @@ -84,4 +92,11 @@ bool CSVDoc::ViewManager::closeRequest (View *view) } return true; +} + +void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document) +{ + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + if ((*iter)->getDocument()==document) + (*iter)->updateDocumentState(); } \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 765fafbea..1565b7c37 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -3,6 +3,8 @@ #include +#include + namespace CSMDoc { class Document; @@ -13,8 +15,10 @@ namespace CSVDoc { class View; - class ViewManager + class ViewManager : public QObject { + Q_OBJECT + CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; std::vector mClosed; @@ -29,7 +33,7 @@ namespace CSVDoc ViewManager (CSMDoc::DocumentManager& documentManager); - ~ViewManager(); + virtual ~ViewManager(); View *addView (CSMDoc::Document *document); ///< The ownership of the returned view is not transferred. @@ -39,8 +43,9 @@ namespace CSVDoc bool closeRequest (View *view); + private slots: - + void documentStateChanged (int state, CSMDoc::Document *document); }; } From 5838929371d37b2f4b8771d3c1a8fb17b3989b06 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Nov 2012 00:36:01 +0100 Subject: [PATCH 016/916] implemented a dummy save function (does not actually save anything) --- apps/opencs/model/doc/document.cpp | 30 ++++++++++++++++++++++++++++ apps/opencs/model/doc/document.hpp | 15 +++++++++++++- apps/opencs/view/doc/view.cpp | 15 ++++++++++++++ apps/opencs/view/doc/view.hpp | 4 ++++ apps/opencs/view/doc/viewmanager.cpp | 2 +- 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 8770b3b90..8788ecb9f 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -4,6 +4,10 @@ CSMDoc::Document::Document() { connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); + + // dummy implementation -> remove when proper save is implemented. + mSaveCount = 0; + connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); } QUndoStack& CSMDoc::Document::getUndoStack() @@ -18,10 +22,36 @@ int CSMDoc::Document::getState() const if (!mUndoStack.isClean()) state |= State_Modified; + if (mSaveCount) + state |= State_Locked | State_Saving; + return state; } +void CSMDoc::Document::save() +{ + mSaveCount = 1; + mSaveTimer.start (500); +} + +void CSMDoc::Document::abortSave() +{ + mSaveTimer.stop(); +} + void CSMDoc::Document::modificationStateChanged (bool clean) { emit stateChanged (getState(), this); +} + +void CSMDoc::Document::saving() +{ + ++mSaveCount; + + if (mSaveCount>15) + { + mSaveCount = 0; + mSaveTimer.stop(); + mUndoStack.setClean(); + } } \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 0499aaf9f..90589b09c 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace CSMDoc { @@ -14,11 +15,16 @@ namespace CSMDoc enum State { - State_Modified = 1 + State_Modified = 1, + State_Locked = 2, + State_Saving = 4 }; QUndoStack mUndoStack; + int mSaveCount; ///< dummy implementation -> remove when proper save is implemented. + QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented. + // not implemented Document (const Document&); Document& operator= (const Document&); @@ -31,6 +37,10 @@ namespace CSMDoc int getState() const; + void save(); + + void abortSave(); + signals: void stateChanged (int state, CSMDoc::Document *document); @@ -38,6 +48,9 @@ namespace CSMDoc private slots: void modificationStateChanged (bool clean); + + void saving(); + ///< dummy implementation -> remove when proper save is implemented. }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index be753e216..59852bef0 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -16,6 +16,15 @@ void CSVDoc::View::closeEvent (QCloseEvent *event) event->ignore(); } +void CSVDoc::View::setupFileMenu() +{ + QMenu *file = menuBar()->addMenu (tr ("&File")); + + QAction *save = new QAction (tr ("&Save"), this); + connect (save, SIGNAL (triggered()), this, SLOT (save())); + file->addAction (save); +} + void CSVDoc::View::setupEditMenu() { QMenu *edit = menuBar()->addMenu (tr ("&Edit")); @@ -45,6 +54,7 @@ void CSVDoc::View::setupViewMenu() void CSVDoc::View::setupUi() { + setupFileMenu(); setupEditMenu(); setupViewMenu(); } @@ -105,4 +115,9 @@ void CSVDoc::View::newView() void CSVDoc::View::test() { mDocument->getUndoStack().push (new QUndoCommand()); +} + +void CSVDoc::View::save() +{ + mDocument->save(); } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 67eafe2d5..be7d23fd0 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -31,6 +31,8 @@ namespace CSVDoc void closeEvent (QCloseEvent *event); + void setupFileMenu(); + void setupEditMenu(); void setupViewMenu(); @@ -57,6 +59,8 @@ namespace CSVDoc void newView(); void test(); + + void save(); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index ad391dabe..c7f147660 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -99,4 +99,4 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) (*iter)->updateDocumentState(); -} \ No newline at end of file +} From 931eb08114184442f856239f1f32f1da25ddde6d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Nov 2012 00:51:04 +0100 Subject: [PATCH 017/916] implemented edit locking (used during saves) --- apps/opencs/model/doc/document.cpp | 3 +++ apps/opencs/view/doc/view.cpp | 26 ++++++++++++++++++++------ apps/opencs/view/doc/view.hpp | 7 +++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 8788ecb9f..16af492a9 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -32,11 +32,13 @@ void CSMDoc::Document::save() { mSaveCount = 1; mSaveTimer.start (500); + emit stateChanged (getState(), this); } void CSMDoc::Document::abortSave() { mSaveTimer.stop(); + emit stateChanged (getState(), this); } void CSMDoc::Document::modificationStateChanged (bool clean) @@ -53,5 +55,6 @@ void CSMDoc::Document::saving() mSaveCount = 0; mSaveTimer.stop(); mUndoStack.setClean(); + emit stateChanged (getState(), this); } } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 59852bef0..85db5e51f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -23,24 +23,26 @@ void CSVDoc::View::setupFileMenu() QAction *save = new QAction (tr ("&Save"), this); connect (save, SIGNAL (triggered()), this, SLOT (save())); file->addAction (save); + mEditingActions.push_back (save); } void CSVDoc::View::setupEditMenu() { QMenu *edit = menuBar()->addMenu (tr ("&Edit")); - QAction *undo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo")); - undo->setShortcuts (QKeySequence::Undo); - edit->addAction (undo); + mUndo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo")); + mUndo->setShortcuts (QKeySequence::Undo); + edit->addAction (mUndo); - QAction *redo = mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); - redo->setShortcuts (QKeySequence::Redo); - edit->addAction (redo); + mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); + mRedo->setShortcuts (QKeySequence::Redo); + edit->addAction (mRedo); // test QAction *test = new QAction (tr ("&Test Command"), this); connect (test, SIGNAL (triggered()), this, SLOT (test())); edit->addAction (test); + mEditingActions.push_back (test); } void CSVDoc::View::setupViewMenu() @@ -74,6 +76,17 @@ void CSVDoc::View::updateTitle() setWindowTitle (stream.str().c_str()); } +void CSVDoc::View::updateActions() +{ + bool editing = !(mDocument->getState() & CSMDoc::Document::State_Locked); + + for (std::vector::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter) + (*iter)->setEnabled (editing); + + mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo()); + mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo()); +} + CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { @@ -105,6 +118,7 @@ void CSVDoc::View::setIndex (int viewIndex, int totalViews) void CSVDoc::View::updateDocumentState() { updateTitle(); + updateActions(); } void CSVDoc::View::newView() diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index be7d23fd0..bab142959 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -1,6 +1,8 @@ #ifndef CSV_DOC_VIEW_H #define CSV_DOC_VIEW_H +#include + #include class QAction; @@ -22,6 +24,9 @@ namespace CSVDoc CSMDoc::Document *mDocument; int mViewIndex; int mViewTotal; + QAction *mUndo; + QAction *mRedo; + std::vector mEditingActions; // not implemented View (const View&); @@ -41,6 +46,8 @@ namespace CSVDoc void updateTitle(); + void updateActions(); + public: View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); From 03aacd326395c8548d5091bf5b83b92e6b969d69 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Nov 2012 10:25:34 +0100 Subject: [PATCH 018/916] added progress tracking --- apps/opencs/model/doc/document.cpp | 5 ++++- apps/opencs/model/doc/document.hpp | 5 ++++- apps/opencs/view/doc/view.cpp | 5 +++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/doc/viewmanager.cpp | 11 +++++++++++ apps/opencs/view/doc/viewmanager.hpp | 2 ++ 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 16af492a9..3c2c5cd8a 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -23,7 +23,7 @@ int CSMDoc::Document::getState() const state |= State_Modified; if (mSaveCount) - state |= State_Locked | State_Saving; + state |= State_Locked | State_Saving | State_Progress; return state; } @@ -33,6 +33,7 @@ void CSMDoc::Document::save() mSaveCount = 1; mSaveTimer.start (500); emit stateChanged (getState(), this); + emit progress (1, 16, this); } void CSMDoc::Document::abortSave() @@ -50,6 +51,8 @@ void CSMDoc::Document::saving() { ++mSaveCount; + emit progress (mSaveCount, 16, this); + if (mSaveCount>15) { mSaveCount = 0; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 90589b09c..b1c9ead86 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -17,7 +17,8 @@ namespace CSMDoc { State_Modified = 1, State_Locked = 2, - State_Saving = 4 + State_Saving = 4, + State_Progress = 8 }; QUndoStack mUndoStack; @@ -45,6 +46,8 @@ namespace CSMDoc void stateChanged (int state, CSMDoc::Document *document); + void progress (int current, int max, CSMDoc::Document *document); + private slots: void modificationStateChanged (bool clean); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 85db5e51f..8f3efc673 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -121,6 +121,11 @@ void CSVDoc::View::updateDocumentState() updateActions(); } +void CSVDoc::View::updateProgress (int current, int max) +{ + +} + void CSVDoc::View::newView() { mViewManager.addView (mDocument); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index bab142959..ab945188f 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -61,6 +61,8 @@ namespace CSVDoc void updateDocumentState(); + void updateProgress (int current, int max); + private slots: void newView(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index c7f147660..752501b19 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -48,6 +48,9 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) // new document connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (documentStateChanged (int, CSMDoc::Document *))); + + connect (document, SIGNAL (progress (int, int, CSMDoc::Document *)), + this, SLOT (progress (int, int, CSMDoc::Document *))); } View *view = new View (*this, document, countViews (document)+1); @@ -80,6 +83,7 @@ bool CSVDoc::ViewManager::closeRequest (View *view) { bool last = countViews (view->getDocument())<=1; + /// \todo check if save is in progress -> warn user about possible data loss /// \todo check if document has not been saved -> return false and start close dialogue mViews.erase (iter); @@ -100,3 +104,10 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc if ((*iter)->getDocument()==document) (*iter)->updateDocumentState(); } + +void CSVDoc::ViewManager::progress (int current, int max, CSMDoc::Document *document) +{ + for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) + if ((*iter)->getDocument()==document) + (*iter)->updateProgress (current, max); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 1565b7c37..8cfc36f3f 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -46,6 +46,8 @@ namespace CSVDoc private slots: void documentStateChanged (int state, CSMDoc::Document *document); + + void progress (int current, int max, CSMDoc::Document *document); }; } From 04158d03b05cc63ba238835821a4125ea0ba8869 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Nov 2012 10:30:14 +0100 Subject: [PATCH 019/916] clean up properly after closing a top level window --- apps/opencs/view/doc/viewmanager.cpp | 5 +---- apps/opencs/view/doc/viewmanager.hpp | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 752501b19..7f94f52a2 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -36,9 +36,6 @@ CSVDoc::ViewManager::~ViewManager() { for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; - - for (std::vector::iterator iter (mClosed.begin()); iter!=mClosed.end(); ++iter) - delete *iter; } CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) @@ -87,7 +84,7 @@ bool CSVDoc::ViewManager::closeRequest (View *view) /// \todo check if document has not been saved -> return false and start close dialogue mViews.erase (iter); - mClosed.push_back (view); + view->deleteLater(); if (last) mDocumentManager.removeDocument (view->getDocument()); diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 8cfc36f3f..bcf6dc59e 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -21,7 +21,6 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; - std::vector mClosed; // not implemented ViewManager (const ViewManager&); From eaa58e0530c3624ee186f5f43ef02f63203354a3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Nov 2012 10:52:46 +0100 Subject: [PATCH 020/916] preparations for multiple parallel progress-type operations --- apps/opencs/model/doc/document.cpp | 6 +++--- apps/opencs/model/doc/document.hpp | 5 ++--- apps/opencs/view/doc/view.cpp | 11 ++++++----- apps/opencs/view/doc/view.hpp | 3 ++- apps/opencs/view/doc/viewmanager.cpp | 8 ++++---- apps/opencs/view/doc/viewmanager.hpp | 2 +- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 3c2c5cd8a..c4f830531 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -23,7 +23,7 @@ int CSMDoc::Document::getState() const state |= State_Modified; if (mSaveCount) - state |= State_Locked | State_Saving | State_Progress; + state |= State_Locked | State_Saving; return state; } @@ -33,7 +33,7 @@ void CSMDoc::Document::save() mSaveCount = 1; mSaveTimer.start (500); emit stateChanged (getState(), this); - emit progress (1, 16, this); + emit progress (1, 16, State_Saving, this); } void CSMDoc::Document::abortSave() @@ -51,7 +51,7 @@ void CSMDoc::Document::saving() { ++mSaveCount; - emit progress (mSaveCount, 16, this); + emit progress (mSaveCount, 16, State_Saving, this); if (mSaveCount>15) { diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index b1c9ead86..8553427a1 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -17,8 +17,7 @@ namespace CSMDoc { State_Modified = 1, State_Locked = 2, - State_Saving = 4, - State_Progress = 8 + State_Saving = 4 }; QUndoStack mUndoStack; @@ -46,7 +45,7 @@ namespace CSMDoc void stateChanged (int state, CSMDoc::Document *document); - void progress (int current, int max, CSMDoc::Document *document); + void progress (int current, int max, int type, CSMDoc::Document *document); private slots: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 8f3efc673..3e9701669 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -20,10 +20,9 @@ void CSVDoc::View::setupFileMenu() { QMenu *file = menuBar()->addMenu (tr ("&File")); - QAction *save = new QAction (tr ("&Save"), this); - connect (save, SIGNAL (triggered()), this, SLOT (save())); - file->addAction (save); - mEditingActions.push_back (save); + mSave = new QAction (tr ("&Save"), this); + connect (mSave, SIGNAL (triggered()), this, SLOT (save())); + file->addAction (mSave); } void CSVDoc::View::setupEditMenu() @@ -85,6 +84,8 @@ void CSVDoc::View::updateActions() mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo()); mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo()); + + mSave->setEnabled (!(mDocument->getState() & CSMDoc::Document::State_Saving)); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) @@ -121,7 +122,7 @@ void CSVDoc::View::updateDocumentState() updateActions(); } -void CSVDoc::View::updateProgress (int current, int max) +void CSVDoc::View::updateProgress (int current, int max, int type) { } diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index ab945188f..1836ced8b 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -26,6 +26,7 @@ namespace CSVDoc int mViewTotal; QAction *mUndo; QAction *mRedo; + QAction *mSave; std::vector mEditingActions; // not implemented @@ -61,7 +62,7 @@ namespace CSVDoc void updateDocumentState(); - void updateProgress (int current, int max); + void updateProgress (int current, int max, int type); private slots: diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 7f94f52a2..ed31fdb75 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -46,8 +46,8 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (documentStateChanged (int, CSMDoc::Document *))); - connect (document, SIGNAL (progress (int, int, CSMDoc::Document *)), - this, SLOT (progress (int, int, CSMDoc::Document *))); + connect (document, SIGNAL (progress (int, int, int, CSMDoc::Document *)), + this, SLOT (progress (int, int, int, CSMDoc::Document *))); } View *view = new View (*this, document, countViews (document)+1); @@ -102,9 +102,9 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc (*iter)->updateDocumentState(); } -void CSVDoc::ViewManager::progress (int current, int max, CSMDoc::Document *document) +void CSVDoc::ViewManager::progress (int current, int max, int type, CSMDoc::Document *document) { for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) - (*iter)->updateProgress (current, max); + (*iter)->updateProgress (current, max, type); } \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index bcf6dc59e..eac490250 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -46,7 +46,7 @@ namespace CSVDoc void documentStateChanged (int state, CSMDoc::Document *document); - void progress (int current, int max, CSMDoc::Document *document); + void progress (int current, int max, int type, CSMDoc::Document *document); }; } From 2fc183d595a59ff9d84b67dc32448234ebe4d6ff Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Nov 2012 12:20:35 +0100 Subject: [PATCH 021/916] added operations progress bar --- apps/opencs/CMakeLists.txt | 4 +-- apps/opencs/model/doc/document.cpp | 13 +++++--- apps/opencs/model/doc/document.hpp | 4 +-- apps/opencs/view/doc/operation.cpp | 49 ++++++++++++++++++++++++++++ apps/opencs/view/doc/operation.hpp | 31 ++++++++++++++++++ apps/opencs/view/doc/operations.cpp | 47 ++++++++++++++++++++++++++ apps/opencs/view/doc/operations.hpp | 37 +++++++++++++++++++++ apps/opencs/view/doc/view.cpp | 20 ++++++++++-- apps/opencs/view/doc/view.hpp | 4 ++- apps/opencs/view/doc/viewmanager.cpp | 8 ++--- apps/opencs/view/doc/viewmanager.hpp | 2 +- 11 files changed, 202 insertions(+), 17 deletions(-) create mode 100644 apps/opencs/view/doc/operation.cpp create mode 100644 apps/opencs/view/doc/operation.hpp create mode 100644 apps/opencs/view/doc/operations.cpp create mode 100644 apps/opencs/view/doc/operations.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d7f113447..66b9f4942 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -4,7 +4,7 @@ set (OPENCS_SRC model/doc/documentmanager.cpp model/doc/document.cpp - view/doc/viewmanager.cpp view/doc/view.cpp + view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp ) set (OPENCS_HDR @@ -12,7 +12,7 @@ set (OPENCS_HDR model/doc/documentmanager.hpp model/doc/document.hpp - view/doc/viewmanager.hpp view/doc/view.hpp + view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp ) set (OPENCS_US diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index c4f830531..473d72375 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -33,13 +33,16 @@ void CSMDoc::Document::save() mSaveCount = 1; mSaveTimer.start (500); emit stateChanged (getState(), this); - emit progress (1, 16, State_Saving, this); + emit progress (1, 16, State_Saving, 1, this); } -void CSMDoc::Document::abortSave() +void CSMDoc::Document::abortOperation (int type) { - mSaveTimer.stop(); - emit stateChanged (getState(), this); + if (type==State_Saving) + { + mSaveTimer.stop(); + emit stateChanged (getState(), this); + } } void CSMDoc::Document::modificationStateChanged (bool clean) @@ -51,7 +54,7 @@ void CSMDoc::Document::saving() { ++mSaveCount; - emit progress (mSaveCount, 16, State_Saving, this); + emit progress (mSaveCount, 16, State_Saving, 1, this); if (mSaveCount>15) { diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 8553427a1..3bed0151d 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -39,13 +39,13 @@ namespace CSMDoc void save(); - void abortSave(); + void abortOperation (int type); signals: void stateChanged (int state, CSMDoc::Document *document); - void progress (int current, int max, int type, CSMDoc::Document *document); + void progress (int current, int max, int type, int threads, CSMDoc::Document *document); private slots: diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp new file mode 100644 index 000000000..cd9477557 --- /dev/null +++ b/apps/opencs/view/doc/operation.cpp @@ -0,0 +1,49 @@ + +#include "operation.hpp" + +#include + +#include "../../model/doc/document.hpp" + +void CSVDoc::Operation::updateLabel (int threads) +{ + if (threads==-1 || ((threads==0)!=mStalling)) + { + std::string name ("unknown operation"); + + switch (mType) + { + case CSMDoc::Document::State_Saving: name = "saving"; break; + } + + std::ostringstream stream; + + if ((mStalling = (threads<=0))) + { + stream << name << " (waiting for a free worker thread)"; + } + else + { + stream << name << " (%p%)"; + } + + setFormat (stream.str().c_str()); + } +} + +CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) +{ + updateLabel(); +} + +void CSVDoc::Operation::setProgress (int current, int max, int threads) +{ + updateLabel (threads); + setRange (0, max); + setValue (current); +} + +int CSVDoc::Operation::getType() const +{ + return mType; +} \ No newline at end of file diff --git a/apps/opencs/view/doc/operation.hpp b/apps/opencs/view/doc/operation.hpp new file mode 100644 index 000000000..362725b6f --- /dev/null +++ b/apps/opencs/view/doc/operation.hpp @@ -0,0 +1,31 @@ +#ifndef CSV_DOC_OPERATION_H +#define CSV_DOC_OPERATION_H + +#include + +namespace CSVDoc +{ + class Operation : public QProgressBar + { + Q_OBJECT + + int mType; + bool mStalling; + + // not implemented + Operation (const Operation&); + Operation& operator= (const Operation&); + + void updateLabel (int threads = -1); + + public: + + Operation (int type); + + void setProgress (int current, int max, int threads); + + int getType() const; + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp new file mode 100644 index 000000000..ba444a119 --- /dev/null +++ b/apps/opencs/view/doc/operations.cpp @@ -0,0 +1,47 @@ + +#include "operations.hpp" + +#include + +#include "operation.hpp" + +CSVDoc::Operations::Operations() +{ + /// \todo make widget height fixed (exactly the height required to display all operations) + + setFeatures (QDockWidget::NoDockWidgetFeatures); + + QWidget *widget = new QWidget; + setWidget (widget); + + mLayout = new QVBoxLayout; + + widget->setLayout (mLayout); +} + +void CSVDoc::Operations::setProgress (int current, int max, int type, int threads) +{ + for (std::vector::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter) + if ((*iter)->getType()==type) + { + (*iter)->setProgress (current, max, threads); + return; + } + + Operation *operation = new Operation (type); + + mLayout->addWidget (operation); + mOperations.push_back (operation); + operation->setProgress (current, max, threads); +} + +void CSVDoc::Operations::quitOperation (int type) +{ + for (std::vector::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter) + if ((*iter)->getType()==type) + { + delete *iter; + mOperations.erase (iter); + break; + } +} \ No newline at end of file diff --git a/apps/opencs/view/doc/operations.hpp b/apps/opencs/view/doc/operations.hpp new file mode 100644 index 000000000..b96677450 --- /dev/null +++ b/apps/opencs/view/doc/operations.hpp @@ -0,0 +1,37 @@ +#ifndef CSV_DOC_OPERATIONS_H +#define CSV_DOC_OPERATIONS_H + +#include + +#include + +class QVBoxLayout; + +namespace CSVDoc +{ + class Operation; + + class Operations : public QDockWidget + { + Q_OBJECT + + QVBoxLayout *mLayout; + std::vector mOperations; + + // not implemented + Operations (const Operations&); + Operations& operator= (const Operations&); + + public: + + Operations(); + + void setProgress (int current, int max, int type, int threads); + ///< Implicitly starts the operation, if it is not running already. + + void quitOperation (int type); + ///< Calling this function for an operation that is not running is a no-op. + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3e9701669..fe018ab3b 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -9,6 +9,7 @@ #include "../../model/doc/document.hpp" #include "viewmanager.hpp" +#include "operations.hpp" void CSVDoc::View::closeEvent (QCloseEvent *event) { @@ -94,6 +95,9 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to setCentralWidget (new QWidget); resize (200, 200); + mOperations = new Operations; + addDockWidget (Qt::BottomDockWidgetArea, mOperations); + updateTitle(); setupUi(); @@ -120,11 +124,23 @@ void CSVDoc::View::updateDocumentState() { updateTitle(); updateActions(); + + static const int operations[] = + { + CSMDoc::Document::State_Saving, + -1 // end marker + }; + + int state = mDocument->getState() ; + + for (int i=0; operations[i]!=-1; ++i) + if (!(state & operations[i])) + mOperations->quitOperation (operations[i]); } -void CSVDoc::View::updateProgress (int current, int max, int type) +void CSVDoc::View::updateProgress (int current, int max, int type, int threads) { - + mOperations->setProgress (current, max, type, threads); } void CSVDoc::View::newView() diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 1836ced8b..191af36b5 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -15,6 +15,7 @@ namespace CSMDoc namespace CSVDoc { class ViewManager; + class Operations; class View : public QMainWindow { @@ -28,6 +29,7 @@ namespace CSVDoc QAction *mRedo; QAction *mSave; std::vector mEditingActions; + Operations *mOperations; // not implemented View (const View&); @@ -62,7 +64,7 @@ namespace CSVDoc void updateDocumentState(); - void updateProgress (int current, int max, int type); + void updateProgress (int current, int max, int type, int threads); private slots: diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index ed31fdb75..673afbad8 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -46,8 +46,8 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (documentStateChanged (int, CSMDoc::Document *))); - connect (document, SIGNAL (progress (int, int, int, CSMDoc::Document *)), - this, SLOT (progress (int, int, int, CSMDoc::Document *))); + connect (document, SIGNAL (progress (int, int, int, int, CSMDoc::Document *)), + this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); } View *view = new View (*this, document, countViews (document)+1); @@ -102,9 +102,9 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc (*iter)->updateDocumentState(); } -void CSVDoc::ViewManager::progress (int current, int max, int type, CSMDoc::Document *document) +void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, CSMDoc::Document *document) { for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) - (*iter)->updateProgress (current, max, type); + (*iter)->updateProgress (current, max, type, threads); } \ No newline at end of file diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index eac490250..caf75a0cd 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -46,7 +46,7 @@ namespace CSVDoc void documentStateChanged (int state, CSMDoc::Document *document); - void progress (int current, int max, int type, CSMDoc::Document *document); + void progress (int current, int max, int type, int threads, CSMDoc::Document *document); }; } From 997386d8736b036bdb3dd1a7a38e904d4793a755 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Nov 2012 13:15:45 +0100 Subject: [PATCH 022/916] implemented world verify function (doesn't do anything yet; mostly meant as a test for multi-operation interface) --- apps/opencs/model/doc/document.cpp | 34 ++++++++++++++++++++++++++++++ apps/opencs/model/doc/document.hpp | 11 +++++++++- apps/opencs/view/doc/operation.cpp | 3 +++ apps/opencs/view/doc/view.cpp | 18 +++++++++++++++- apps/opencs/view/doc/view.hpp | 5 +++++ 5 files changed, 69 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 473d72375..5c39e16c0 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -8,6 +8,10 @@ CSMDoc::Document::Document() // dummy implementation -> remove when proper save is implemented. mSaveCount = 0; connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); + + // dummy implementation -> remove when proper verify is implemented. + mVerifyCount = 0; + connect (&mVerifyTimer, SIGNAL(timeout()), this, SLOT (verifying())); } QUndoStack& CSMDoc::Document::getUndoStack() @@ -25,6 +29,9 @@ int CSMDoc::Document::getState() const if (mSaveCount) state |= State_Locked | State_Saving; + if (mVerifyCount) + state |= State_Locked | State_Verifying; + return state; } @@ -36,6 +43,14 @@ void CSMDoc::Document::save() emit progress (1, 16, State_Saving, 1, this); } +void CSMDoc::Document::verify() +{ + mVerifyCount = 1; + mVerifyTimer.start (500); + emit stateChanged (getState(), this); + emit progress (1, 20, State_Verifying, 1, this); +} + void CSMDoc::Document::abortOperation (int type) { if (type==State_Saving) @@ -43,6 +58,11 @@ void CSMDoc::Document::abortOperation (int type) mSaveTimer.stop(); emit stateChanged (getState(), this); } + else if (type==State_Verifying) + { + mVerifyTimer.stop(); + emit stateChanged (getState(), this); + } } void CSMDoc::Document::modificationStateChanged (bool clean) @@ -63,4 +83,18 @@ void CSMDoc::Document::saving() mUndoStack.setClean(); emit stateChanged (getState(), this); } +} + +void CSMDoc::Document::verifying() +{ + ++mVerifyCount; + + emit progress (mVerifyCount, 20, State_Verifying, 1, this); + + if (mVerifyCount>19) + { + mVerifyCount = 0; + mVerifyTimer.stop(); + emit stateChanged (getState(), this); + } } \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 3bed0151d..e691bb38f 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -17,7 +17,8 @@ namespace CSMDoc { State_Modified = 1, State_Locked = 2, - State_Saving = 4 + State_Saving = 4, + State_Verifying = 8 }; QUndoStack mUndoStack; @@ -25,6 +26,9 @@ namespace CSMDoc int mSaveCount; ///< dummy implementation -> remove when proper save is implemented. QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented. + int mVerifyCount; ///< dummy implementation -> remove when proper verify is implemented. + QTimer mVerifyTimer; ///< dummy implementation -> remove when proper verify is implemented. + // not implemented Document (const Document&); Document& operator= (const Document&); @@ -39,6 +43,8 @@ namespace CSMDoc void save(); + void verify(); + void abortOperation (int type); signals: @@ -53,6 +59,9 @@ namespace CSMDoc void saving(); ///< dummy implementation -> remove when proper save is implemented. + + void verifying(); + ///< dummy implementation -> remove when proper verify is implemented. }; } diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index cd9477557..02a93f9c5 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -14,6 +14,7 @@ void CSVDoc::Operation::updateLabel (int threads) switch (mType) { case CSMDoc::Document::State_Saving: name = "saving"; break; + case CSMDoc::Document::State_Verifying: name = "verifying"; break; } std::ostringstream stream; @@ -34,6 +35,8 @@ void CSVDoc::Operation::updateLabel (int threads) CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) { updateLabel(); + + /// \todo assign different progress bar colours to allow the user to distinguish easily between operation types } void CSVDoc::Operation::setProgress (int current, int max, int threads) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index fe018ab3b..8ed1f83b8 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -54,11 +54,21 @@ void CSVDoc::View::setupViewMenu() view->addAction (newWindow); } +void CSVDoc::View::setupWorldMenu() +{ + QMenu *world = menuBar()->addMenu (tr ("&World")); + + mVerify = new QAction (tr ("&Verify"), this); + connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); + world->addAction (mVerify); +} + void CSVDoc::View::setupUi() { setupFileMenu(); setupEditMenu(); setupViewMenu(); + setupWorldMenu(); } void CSVDoc::View::updateTitle() @@ -87,6 +97,7 @@ void CSVDoc::View::updateActions() mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo()); mSave->setEnabled (!(mDocument->getState() & CSMDoc::Document::State_Saving)); + mVerify->setEnabled (!(mDocument->getState() & CSMDoc::Document::State_Verifying)); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) @@ -127,7 +138,7 @@ void CSVDoc::View::updateDocumentState() static const int operations[] = { - CSMDoc::Document::State_Saving, + CSMDoc::Document::State_Saving, CSMDoc::Document::State_Verifying, -1 // end marker }; @@ -156,4 +167,9 @@ void CSVDoc::View::test() void CSVDoc::View::save() { mDocument->save(); +} + +void CSVDoc::View::verify() +{ + mDocument->verify(); } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 191af36b5..15394a7d8 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -28,6 +28,7 @@ namespace CSVDoc QAction *mUndo; QAction *mRedo; QAction *mSave; + QAction *mVerify; std::vector mEditingActions; Operations *mOperations; @@ -45,6 +46,8 @@ namespace CSVDoc void setupViewMenu(); + void setupWorldMenu(); + void setupUi(); void updateTitle(); @@ -73,6 +76,8 @@ namespace CSVDoc void test(); void save(); + + void verify(); }; } From 303506d24b00a0bbcbb7f796fa071b5f750c3be9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 23 Nov 2012 14:05:49 +0100 Subject: [PATCH 023/916] added new document function --- apps/opencs/editor.cpp | 12 ++++++++++-- apps/opencs/editor.hpp | 14 +++++++++++--- apps/opencs/model/doc/document.cpp | 9 ++++++++- apps/opencs/model/doc/document.hpp | 9 ++++++++- apps/opencs/model/doc/documentmanager.cpp | 4 ++-- apps/opencs/model/doc/documentmanager.hpp | 3 ++- apps/opencs/view/doc/view.cpp | 8 ++++++-- apps/opencs/view/doc/view.hpp | 4 ++++ apps/opencs/view/doc/viewmanager.cpp | 2 ++ apps/opencs/view/doc/viewmanager.hpp | 4 ++++ 10 files changed, 57 insertions(+), 12 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 264ae7543..c03a1dc5d 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,20 +1,28 @@ #include "editor.hpp" +#include + #include -CS::Editor::Editor() : mViewManager (mDocumentManager) +CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) { + connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); } void CS::Editor::createDocument() { - CSMDoc::Document *document = mDocumentManager.addDocument(); + std::ostringstream stream; + + stream << "NewDocument" << (++mNewDocumentIndex); + + CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); mViewManager.addView (document); } int CS::Editor::run() { + /// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects createDocument(); return QApplication::exec(); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 6e183b843..60f7beaf1 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -1,13 +1,19 @@ #ifndef CS_EDITOR_H #define CS_EDITOR_H +#include + #include "model/doc/documentmanager.hpp" #include "view/doc/viewmanager.hpp" namespace CS { - class Editor + class Editor : public QObject { + Q_OBJECT + + int mNewDocumentIndex; ///< \todo remove when the proper new document dialogue is implemented. + CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; @@ -19,10 +25,12 @@ namespace CS Editor(); - void createDocument(); - int run(); ///< \return error status + + public slots: + + void createDocument(); }; } diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 5c39e16c0..cd65e83ae 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,8 +1,10 @@ #include "document.hpp" -CSMDoc::Document::Document() +CSMDoc::Document::Document (const std::string& name) { + mName = name; ///< \todo replace with ESX list + connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); // dummy implementation -> remove when proper save is implemented. @@ -35,6 +37,11 @@ int CSMDoc::Document::getState() const return state; } +const std::string& CSMDoc::Document::getName() const +{ + return mName; +} + void CSMDoc::Document::save() { mSaveCount = 1; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index e691bb38f..0249d8e5c 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -1,6 +1,8 @@ #ifndef CSM_DOC_DOCUMENT_H #define CSM_DOC_DOCUMENT_H +#include + #include #include #include @@ -21,6 +23,7 @@ namespace CSMDoc State_Verifying = 8 }; + std::string mName; ///< \todo replace name with ESX list QUndoStack mUndoStack; int mSaveCount; ///< dummy implementation -> remove when proper save is implemented. @@ -35,12 +38,16 @@ namespace CSMDoc public: - Document(); + Document (const std::string& name); + ///< \todo replace name with ESX list QUndoStack& getUndoStack(); int getState() const; + const std::string& getName() const; + ///< \todo replace with ESX list + void save(); void verify(); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 68595f2d4..8ae2764f2 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -14,9 +14,9 @@ CSMDoc::DocumentManager::~DocumentManager() delete *iter; } -CSMDoc::Document *CSMDoc::DocumentManager::addDocument() +CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::string& name) { - Document *document = new Document; + Document *document = new Document (name); mDocuments.push_back (document); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index f20f3101d..730c7fae1 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -2,6 +2,7 @@ #define CSM_DOC_DOCUMENTMGR_H #include +#include namespace CSMDoc { @@ -20,7 +21,7 @@ namespace CSMDoc ~DocumentManager(); - Document *addDocument(); + Document *addDocument (const std::string& name); ///< The ownership of the returned document is not transferred to the caller. bool removeDocument (Document *document); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 8ed1f83b8..5c7199aa4 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -21,6 +21,10 @@ void CSVDoc::View::setupFileMenu() { QMenu *file = menuBar()->addMenu (tr ("&File")); + QAction *new_ = new QAction (tr ("New"), this); + connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); + file->addAction (new_); + mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); @@ -75,7 +79,7 @@ void CSVDoc::View::updateTitle() { std::ostringstream stream; - stream << "New Document "; + stream << mDocument->getName(); if (mDocument->getState() & CSMDoc::Document::State_Modified) stream << " *"; @@ -104,7 +108,7 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { setCentralWidget (new QWidget); - resize (200, 200); + resize (200, 200); /// \todo get default size from settings and set reasonable minimal size mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 15394a7d8..d15d942fc 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -69,6 +69,10 @@ namespace CSVDoc void updateProgress (int current, int max, int type, int threads); + signals: + + void newDocumentRequest(); + private slots: void newView(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 673afbad8..22847c78b 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -56,6 +56,8 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) view->show(); + connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest())); + updateIndices(); return view; diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index caf75a0cd..5e4b1be07 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -42,6 +42,10 @@ namespace CSVDoc bool closeRequest (View *view); + signals: + + void newDocumentRequest(); + private slots: void documentStateChanged (int state, CSMDoc::Document *document); From 019146756fc0d91ab46b54c696fc33770c0d2f1a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Nov 2012 10:14:43 +0100 Subject: [PATCH 024/916] minor documentation changes regarding future improvements and additions --- apps/opencs/model/doc/document.hpp | 4 +++- apps/opencs/view/doc/operation.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 0249d8e5c..1f73b5437 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -20,7 +20,9 @@ namespace CSMDoc State_Modified = 1, State_Locked = 2, State_Saving = 4, - State_Verifying = 8 + State_Verifying = 8, + State_Compiling = 16, // not implemented yet + State_Searching = 32 // not implemented yet }; std::string mName; ///< \todo replace name with ESX list diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 02a93f9c5..62f006be5 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -34,6 +34,8 @@ void CSVDoc::Operation::updateLabel (int threads) CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) { + /// \todo Add a cancel button or a pop up menu with a cancel item + updateLabel(); /// \todo assign different progress bar colours to allow the user to distinguish easily between operation types From 4c0dcd46a19fea65c1c8bd31f82fbbe9103b7429 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Nov 2012 11:01:53 +0100 Subject: [PATCH 025/916] added UniversalId class --- apps/opencs/CMakeLists.txt | 4 + apps/opencs/model/world/universalid.cpp | 161 ++++++++++++++++++++++++ apps/opencs/model/world/universalid.hpp | 80 ++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 apps/opencs/model/world/universalid.cpp create mode 100644 apps/opencs/model/world/universalid.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 66b9f4942..cb721ac54 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -4,6 +4,8 @@ set (OPENCS_SRC model/doc/documentmanager.cpp model/doc/document.cpp + model/world/universalid.cpp + view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp ) @@ -12,6 +14,8 @@ set (OPENCS_HDR model/doc/documentmanager.hpp model/doc/document.hpp + model/world/universalid.hpp + view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp ) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp new file mode 100644 index 000000000..b56a336a6 --- /dev/null +++ b/apps/opencs/model/world/universalid.cpp @@ -0,0 +1,161 @@ + +#include "universalid.hpp" + +#include +#include +#include + +namespace +{ + struct TypeData + { + CSMWorld::UniversalId::Class mClass; + CSMWorld::UniversalId::Type mType; + const char *mName; + }; + + static const TypeData sNoArg[] = + { + { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" }, + + { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker + }; + + static const TypeData sIdArg[] = + { + + { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker + }; + + static const TypeData sIndexArg[] = + { + + { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker + }; +} + +CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_None), mType (type), mIndex (0) +{ + for (int i=0; sNoArg[i].mName; ++i) + if (type==sNoArg[i].mType) + { + mClass = sNoArg[i].mClass; + return; + } + + throw std::logic_error ("invalid argument-less UniversalId type"); +} + +CSMWorld::UniversalId::UniversalId (Type type, const std::string& id) +: mArgumentType (ArgumentType_Id), mType (type), mId (id), mIndex (0) +{ + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mType) + { + mClass = sIdArg[i].mClass; + return; + } + + throw std::logic_error ("invalid ID argument UniversalId type"); +} + +CSMWorld::UniversalId::UniversalId (Type type, int index) +: mArgumentType (ArgumentType_Index), mType (type), mIndex (index) +{ + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mType) + { + mClass = sIndexArg[i].mClass; + return; + } + + throw std::logic_error ("invalid index argument UniversalId type"); +} + +CSMWorld::UniversalId::Class CSMWorld::UniversalId::getClass() const +{ + return mClass; +} + +CSMWorld::UniversalId::ArgumentType CSMWorld::UniversalId::getArgumentType() const +{ + return mArgumentType; +} + +CSMWorld::UniversalId::Type CSMWorld::UniversalId::getType() const +{ + return mType; +} + +const std::string& CSMWorld::UniversalId::getId() const +{ + if (mArgumentType!=ArgumentType_Id) + throw std::logic_error ("invalid access to ID of non-ID UniversalId"); + + return mId; +} + +int CSMWorld::UniversalId::getIndex() const +{ + if (mArgumentType!=ArgumentType_Index) + throw std::logic_error ("invalid access to index of non-index UniversalId"); + + return mIndex; +} + +bool CSMWorld::UniversalId::isEqual (const UniversalId& universalId) const +{ + if (mClass!=universalId.mClass || mArgumentType!=universalId.mArgumentType || mType!=universalId.mType) + return false; + + switch (mArgumentType) + { + case ArgumentType_Id: return mId==universalId.mId; + case ArgumentType_Index: return mIndex==universalId.mIndex; + + default: return true; + } +} + +std::string CSMWorld::UniversalId::getTypeName() const +{ + const TypeData *typeData = mArgumentType==ArgumentType_None ? sNoArg : + (mArgumentType==ArgumentType_Id ? sIdArg : sIndexArg); + + for (int i=0; typeData[i].mName; ++i) + if (typeData[i].mType==mType) + return typeData[i].mName; + + throw std::logic_error ("failed to retrieve UniversalId type name"); +} + +std::string CSMWorld::UniversalId::toString() const +{ + std::ostringstream stream; + + stream << getTypeName(); + + switch (mArgumentType) + { + case ArgumentType_None: break; + case ArgumentType_Id: stream << " " << mId; + case ArgumentType_Index: stream << " " << mIndex; + } + + return stream.str(); +} + +bool operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right) +{ + return left.isEqual (right); +} + +bool operator!= (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right) +{ + return !left.isEqual (right); +} + +std::ostream& operator< (std::ostream& stream, const CSMWorld::UniversalId& universalId) +{ + return stream << universalId.toString(); +} \ No newline at end of file diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp new file mode 100644 index 000000000..6f085cfc2 --- /dev/null +++ b/apps/opencs/model/world/universalid.hpp @@ -0,0 +1,80 @@ +#ifndef CSM_WOLRD_UNIVERSALID_H +#define CSM_WOLRD_UNIVERSALID_H + +#include +#include + +namespace CSMWorld +{ + class UniversalId + { + public: + + enum Class + { + Class_None = 0, + Class_Record, + Class_SubRecord, + Class_RecordList, + Class_Collection, // multiple types of records combined + Class_Transient, // not part of the world data or the project data + Class_NonRecord // record like data that is not part of the world + }; + + enum ArgumentType + { + ArgumentType_None, + ArgumentType_Id, + ArgumentType_Index + }; + + enum Type + { + Type_None + }; + + private: + + Class mClass; + ArgumentType mArgumentType; + Type mType; + std::string mId; + int mIndex; + + public: + + UniversalId (Type type = Type_None); + ///< Using a type for a non-argument-less UniversalId will throw an exception. + + UniversalId (Type type, const std::string& id); + ///< Using a type for a non-ID-argument UniversalId will throw an exception. + + UniversalId (Type type, int index); + ///< Using a type for a non-index-argument UniversalId will throw an exception. + + Class getClass() const; + + ArgumentType getArgumentType() const; + + Type getType() const; + + const std::string& getId() const; + ///< Calling this function for a non-ID type will throw an exception. + + int getIndex() const; + ///< Calling this function for a non-index type will throw an exception. + + bool isEqual (const UniversalId& universalId) const; + + std::string getTypeName() const; + + std::string toString() const; + }; + + bool operator== (const UniversalId& left, const UniversalId& right); + bool operator!= (const UniversalId& left, const UniversalId& right); + + std::ostream& operator< (std::ostream& stream, const UniversalId& universalId); +} + +#endif From eece4226c0427ac2cd7ca5e7b621e6bc8799e8e7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 24 Nov 2012 13:17:21 +0100 Subject: [PATCH 026/916] basic sub view system (very incomplete) --- apps/opencs/CMakeLists.txt | 4 ++++ apps/opencs/view/doc/view.cpp | 32 ++++++++++++++++++++++++++++-- apps/opencs/view/doc/view.hpp | 9 +++++++++ apps/opencs/view/world/subview.cpp | 18 +++++++++++++++++ apps/opencs/view/world/subview.hpp | 28 ++++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/world/subview.cpp create mode 100644 apps/opencs/view/world/subview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index cb721ac54..a56e77d08 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -7,6 +7,8 @@ set (OPENCS_SRC model/world/universalid.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp + + view/world/subview.cpp ) set (OPENCS_HDR @@ -17,6 +19,8 @@ set (OPENCS_HDR model/world/universalid.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp + + view/world/subview.hpp ) set (OPENCS_US diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 5c7199aa4..9bcb8fc5a 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -5,9 +5,12 @@ #include #include +#include #include "../../model/doc/document.hpp" +#include "../world/subview.hpp" + #include "viewmanager.hpp" #include "operations.hpp" @@ -56,6 +59,10 @@ void CSVDoc::View::setupViewMenu() QAction *newWindow = new QAction (tr ("&New View"), this); connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); view->addAction (newWindow); + + QAction *test = new QAction (tr ("Add test Subview"), this); + connect (test, SIGNAL (triggered()), this, SLOT (addTestSubView())); + view->addAction (test); } void CSVDoc::View::setupWorldMenu() @@ -107,8 +114,9 @@ void CSVDoc::View::updateActions() CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - setCentralWidget (new QWidget); - resize (200, 200); /// \todo get default size from settings and set reasonable minimal size + setDockOptions (QMainWindow::AllowNestedDocks); + + resize (300, 300); /// \todo get default size from settings and set reasonable minimal size mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); @@ -158,6 +166,21 @@ void CSVDoc::View::updateProgress (int current, int max, int type, int threads) mOperations->setProgress (current, max, type, threads); } +void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) +{ + /// \todo add an user setting for limiting the number of sub views per top level view. Automatically open a new top level view if this + /// number is exceeded + + /// \todo if the sub view limit setting is one, the sub view title bar should be hidden and the text in the main title bar adjusted + /// accordingly + + /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) + + CSVWorld::SubView *view = new CSVWorld::SubView (id); + addDockWidget (Qt::RightDockWidgetArea, view); + view->show(); +} + void CSVDoc::View::newView() { mViewManager.addView (mDocument); @@ -176,4 +199,9 @@ void CSVDoc::View::save() void CSVDoc::View::verify() { mDocument->verify(); +} + +void CSVDoc::View::addTestSubView() +{ + addSubView (CSMWorld::UniversalId::Type_None); } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index d15d942fc..7a9164e12 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -12,6 +12,11 @@ namespace CSMDoc class Document; } +namespace CSMWorld +{ + class UniversalId; +} + namespace CSVDoc { class ViewManager; @@ -69,6 +74,8 @@ namespace CSVDoc void updateProgress (int current, int max, int type, int threads); + void addSubView (const CSMWorld::UniversalId& id); + signals: void newDocumentRequest(); @@ -82,6 +89,8 @@ namespace CSVDoc void save(); void verify(); + + void addTestSubView(); ///< \todo remove }; } diff --git a/apps/opencs/view/world/subview.cpp b/apps/opencs/view/world/subview.cpp new file mode 100644 index 000000000..23f075980 --- /dev/null +++ b/apps/opencs/view/world/subview.cpp @@ -0,0 +1,18 @@ + +#include "subview.hpp" + +CSVWorld::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) +{ + /// \todo add a button to the title bar that clones this sub view + + setWindowTitle (mUniversalId.toString().c_str()); + + /// \todo remove (for testing only) + setMinimumWidth (100); + setMinimumHeight (60); +} + +CSMWorld::UniversalId CSVWorld::SubView::getUniversalId() const +{ + return mUniversalId; +} diff --git a/apps/opencs/view/world/subview.hpp b/apps/opencs/view/world/subview.hpp new file mode 100644 index 000000000..8488690c8 --- /dev/null +++ b/apps/opencs/view/world/subview.hpp @@ -0,0 +1,28 @@ +#ifndef CSV_WORLD_SUBVIEW_H +#define CSV_WORLD_SUBVIEW_H + +#include "../../model/world/universalid.hpp" + +#include + +namespace CSVWorld +{ + class SubView : public QDockWidget + { + Q_OBJECT + + CSMWorld::UniversalId mUniversalId; + + // not implemented + SubView (const SubView&); + SubView& operator= (SubView&); + + public: + + SubView (const CSMWorld::UniversalId& id); + + CSMWorld::UniversalId getUniversalId() const; + }; +} + +#endif \ No newline at end of file From 896ab44d1e919852aae03be9ecb71378f031b6f5 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 25 Nov 2012 17:19:29 +0100 Subject: [PATCH 027/916] - Add some updated files missing from last commit. - Move plugin dependency test from esmreader.cpp to esmstpre.cpp; fixes crash in omwlauncher. --- apps/openmw/CMakeLists.txt | 7 ++-- apps/openmw/mwrender/terrain.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 8 ++-- apps/openmw/mwworld/cellstore.hpp | 28 ++++++++------ apps/openmw/mwworld/esmstore.cpp | 29 ++++++++++++++ apps/openmw/mwworld/store.hpp | 64 +++++++++++++++++++++---------- apps/openmw/mwworld/worldimp.cpp | 4 +- components/esm/esmreader.cpp | 25 ------------ components/esm/esmreader.hpp | 1 + 9 files changed, 102 insertions(+), 66 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 538f63dc9..e2a2e7f14 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -34,7 +34,7 @@ add_openmw_dir (mwgui ) add_openmw_dir (mwdialogue - dialoguemanagerimp journalimp journalentry quest topic + dialoguemanagerimp journalimp journalentry quest topic filter selectwrapper ) add_openmw_dir (mwscript @@ -50,9 +50,10 @@ add_openmw_dir (mwsound add_openmw_dir (mwworld refdata worldimp physicssystem scene globals class action nullaction actionteleport - containerstore actiontalk actiontake manualref player cellfunctors + containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat + esmstore store recordcmp ) add_openmw_dir (mwclass @@ -62,7 +63,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells - activespells npcstats aipackage aisequence alchemy + activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index d46c2521f..eb5b07af4 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -221,7 +221,7 @@ namespace MWRender // //If we don't sort the ltex indexes, the splatting order may differ between //cells which may lead to inconsistent results when shading between cells - int num = MWBase::Environment::get().getWorld()->getStore().landTexts.getSizePlugin(plugin); + int num = MWBase::Environment::get().getWorld()->getStore().get().getSize(plugin); std::set ltexIndexes; for ( int y = fromY - 1; y < fromY + size + 1; y++ ) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 74856c9ed..ba8f5aa61 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -49,10 +49,10 @@ namespace MWWorld return; // this is a dynamically generated cell -> skipping. // Load references from all plugins that do something with this cell. - for (size_t i = 0; i < cell->mContextList.size(); i++) + for (size_t i = 0; i < mCell->mContextList.size(); i++) { // Reopen the ESM reader and seek to the right position. - int index = cell->mContextList.at(i).index; + int index = mCell->mContextList.at(i).index; mCell->restore (esm[index], i); ESM::CellRef ref; @@ -81,10 +81,10 @@ namespace MWWorld return; // this is a dynamically generated cell -> skipping. // Load references from all plugins that do something with this cell. - for (size_t i = 0; i < cell->mContextList.size(); i++) + for (size_t i = 0; i < mCell->mContextList.size(); i++) { // Reopen the ESM reader and seek to the right position. - int index = cell->mContextList.at(i).index; + int index = mCell->mContextList.at(i).index; mCell->restore (esm[index], i); ESM::CellRef ref; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index b66137cc6..bf7581f6e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -49,26 +49,32 @@ namespace MWWorld { typedef LiveCellRef LiveRef; typedef std::map List; - List list; + List mList; // Search for the given reference in the given reclist from // ESMStore. Insert the reference into the list if a match is // found. If not, throw an exception. - template - void find(ESM::CellRef &ref, const Y& recList) + /// Searches for reference of appropriate type in given ESMStore. + /// If reference exists, loads it into container, throws an exception + /// on miss + void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) { - const X* obj = recList.find(ref.mRefID); - if(obj == NULL) - throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + // for throwing exception on unhandled record type + const MWWorld::Store &store = esmStore.get(); + const X *ptr = store.find(ref.mRefID); - list[ref.mRefnum] = LiveRef(ref, obj); + /// \note redundant because Store::find() throws exception on miss + if (ptr == NULL) { + throw std::runtime_error("Error resolving cell reference " + ref.mRefID); + } + mList[ref.mRefnum] = LiveRef(ref, ptr); } LiveRef *find (const std::string& name) { - for (typename std::map::iterator iter (list.begin()); iter!=list.end(); ++iter) + for (typename std::map::iterator iter (mList.begin()); iter!=mList.end(); ++iter) { - if (iter->second.mData.getCount() > 0 && iter->second.ref.mRefID == name) + if (iter->second.mData.getCount() > 0 && iter->second.mRef.mRefID == name) return &iter->second; } @@ -76,8 +82,8 @@ namespace MWWorld } LiveRef &insert(const LiveRef &item) { - list[item.ref.mRefnum] = item; - return list[item.ref.mRefnum]; + mList[item.mRef.mRefnum] = item; + return mList[item.mRef.mRefnum]; } }; diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 73f5185c9..db444153f 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -3,6 +3,8 @@ #include #include +#include + namespace MWWorld { @@ -25,6 +27,33 @@ void ESMStore::load(ESM::ESMReader &esm) ESM::Dialogue *dialogue = 0; + // Cache parent esX files by tracking their indices in the global list of + // all files/readers used by the engine. This will greaty help to accelerate + // parsing of reference IDs. + size_t index = ~0; + const ESM::ESMReader::MasterList &masters = esm.getMasters(); + std::vector *allPlugins = esm.getGlobalReaderList(); + for (size_t j = 0; j < masters.size(); j++) { + ESM::MasterData &mast = const_cast(masters[j]); + std::string fname = mast.name; + for (size_t i = 0; i < esm.getIndex(); i++) { + const std::string &candidate = allPlugins->at(i).getContext().filename; + std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); + if (fname == fnamecandidate) { + index = i; + break; + } + } + if (index == (size_t)~0) { + // Tried to load a parent file that has not been loaded yet. This is bad, + // the launcher should have taken care of this. + std::string fstring = "File " + fname + " asks for parent file " + masters[j].name + + ", but it has not been loaded yet. Please check your load order."; + esm.fail(fstring); + } + mast.index = index; + } + // Loop through all records while(esm.hasMoreRecs()) { diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fd93f39f1..53f4482bb 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -219,24 +219,31 @@ namespace MWWorld template <> class Store : public StoreBase { - std::vector mStatic; + // For multiple ESM/ESP files we need one list per file. + typedef std::vector LandTextureList; + std::vector mStatic; public: Store() { - mStatic.reserve(128); + mStatic.push_back(LandTextureList()); + LandTextureList <exl = mStatic[0]; + // More than enough to hold Morrowind.esm. Extra lists for plugins will we + // added on-the-fly in a different method. + ltexl.reserve(128); } typedef std::vector::const_iterator iterator; - const ESM::LandTexture *search(size_t index) const { - if (index < mStatic.size()) { - return &mStatic.at(index); - } - return 0; + const ESM::LandTexture *search(size_t index, size_t plugin) const { + assert(plugin < mStatic.size()); + const LandTextureList <exl = mStatic[plugin]; + + assert(index < ltexl.size()); + return <exl.at(index); } - const ESM::LandTexture *find(size_t index) const { - const ESM::LandTexture *ptr = search(index); + const ESM::LandTexture *find(size_t index, size_t plugin) const { + const ESM::LandTexture *ptr = search(index, plugin); if (ptr == 0) { std::ostringstream msg; msg << "Land texture with index " << index << " not found"; @@ -249,23 +256,40 @@ namespace MWWorld return mStatic.size(); } - void load(ESM::ESMReader &esm, const std::string &id) { - ESM::LandTexture ltex; - ltex.load(esm); + int getSize(size_t plugin) const { + assert(plugin < mStatic.size()); + return mStatic[plugin].size(); + } - if (ltex.mIndex >= (int) mStatic.size()) { - mStatic.resize(ltex.mIndex + 1); + void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) { + ESM::LandTexture lt; + lt.load(esm); + lt.mId = id; + + // Make sure we have room for the structure + if (plugin >= mStatic.size()) { + mStatic.resize(plugin+1); } - mStatic[ltex.mIndex] = ltex; - mStatic[ltex.mIndex].mId = id; + LandTextureList <exl = mStatic[plugin]; + if(lt.mIndex + 1 > (int)ltexl.size()) + ltexl.resize(lt.mIndex+1); + + // Store it + ltexl[lt.mIndex] = lt; } - iterator begin() const { - return mStatic.begin(); + void load(ESM::ESMReader &esm, const std::string &id) { + load(esm, id, esm.getIndex()); } - iterator end() const { - return mStatic.end(); + iterator begin(size_t plugin) const { + assert(plugin < mStatic.size()); + return mStatic[plugin].begin(); + } + + iterator end(size_t plugin) const { + assert(plugin < mStatic.size()); + return mStatic[plugin].end(); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 9f2d419f1..1fa23700d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1081,8 +1081,8 @@ namespace MWWorld std::vector result; MWWorld::CellRefList& doors = cell->mDoors; - std::map< MWWorld::LiveCellRef >& refList = doors.mList; - for (std::map >::iterator it = refList.begin(); it != refList.end(); ++it) + CellRefList::List& refList = doors.mList; + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { MWWorld::LiveCellRef& ref = it->second; diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index d1703a2ac..2915a1ce7 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -1,6 +1,5 @@ #include "esmreader.hpp" #include -#include namespace ESM { @@ -62,7 +61,6 @@ void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) { openRaw(_esm, name); - std::string fname = boost::filesystem::path(name).filename().string(); if (getRecName() != "TES3") fail("Not a valid Morrowind file"); @@ -80,29 +78,6 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) MasterData m; m.name = getHString(); m.size = getHNLong("DATA"); - // Cache parent esX files by tracking their indices in the global list of - // all files/readers used by the engine. This will greaty help to accelerate - // parsing of reference IDs. - size_t index = ~0; - // TODO: check for case mismatch, it might be required on Windows. - size_t i = 0; - // FIXME: This is ugly! Make it nicer! - for (; i < idx; i++) { - const std::string &candidate = mGlobalReaderList->at(i).getContext().filename; - std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); - if (m.name == fnamecandidate) { - index = i; - break; - } - } - if (index == (size_t)~0) { - // Tried to load a parent file that has not been loaded yet. This is bad, - // the launcher should have taken care of this. - std::string fstring = "File " + fname + " asks for parent file " + m.name - + ", but it has not been loaded yet. Please check your load order."; - fail(fstring); - } - m.index = index; mMasters.push_back(m); } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index b415009d3..732dbe9bc 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -85,6 +85,7 @@ public: const int getIndex() {return idx;} void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} + std::vector *getGlobalReaderList() {return mGlobalReaderList;} /************************************************************************* * From b103426cf0f1a45efa97ca4d3cf215ee8640dc4f Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 25 Nov 2012 19:07:16 +0100 Subject: [PATCH 028/916] - Partially reimplement deleting objects defined in a parent esX file. - Try to reimplement multiple esX files dropping references in the same file. NOTE: None of these features works. Maybe the code itself does not build. Anyway, after 12 hours of hacking, I am just tired and want to get a snapshot of the code out. --- apps/openmw/mwworld/cellstore.cpp | 2 ++ apps/openmw/mwworld/esmstore.cpp | 11 ++++++- apps/openmw/mwworld/esmstore.hpp | 3 +- apps/openmw/mwworld/store.hpp | 48 ++++++++++++++++++++++++++----- apps/openmw/mwworld/worldimp.cpp | 2 ++ components/esm/loadcell.cpp | 1 + 6 files changed, 58 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ba8f5aa61..ff8368dd1 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -83,6 +83,8 @@ namespace MWWorld // Load references from all plugins that do something with this cell. for (size_t i = 0; i < mCell->mContextList.size(); i++) { + if (mCell->mContextList.size() > 1) + std::cout << "number of lists " << mCell->mContextList.size() << std::endl; // Reopen the ESM reader and seek to the right position. int index = mCell->mContextList.at(i).index; mCell->restore (esm[index], i); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index db444153f..564126797 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -84,6 +84,15 @@ void ESMStore::load(ESM::ESMReader &esm) } else { // Load it std::string id = esm.getHNOString("NAME"); + // ... unless it got deleted! This means that the following record + // has been deleted, and trying to load it using standard assumptions + // on the structure will (probably) fail. + if (esm.isNextSub("DELE")) { + esm.skipRecord(); + all.erase(id); + it->second->remove(id); + continue; + } it->second->load(esm, id); if (n.val==ESM::REC_DIAL) { @@ -113,7 +122,7 @@ void ESMStore::load(ESM::ESMReader &esm) cout << *it << " "; cout << endl; */ - setUp(); + //setUp(); } void ESMStore::setUp() diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 9917254ee..bd8e003f4 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -168,7 +168,8 @@ namespace MWWorld return ptr; } - private: + // This method must be called once, after loading all master/plugin files. This can only be done + // from the outside, so it must be public. void setUp(); }; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 53f4482bb..d4d632eff 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -473,14 +473,48 @@ namespace MWWorld } void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Cell cell; - cell.mName = id; - cell.load(esm); + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded! So first, proceed as usual. + + // All cells have a name record, even nameless exterior cells. + ESM::Cell *cell = new ESM::Cell; + cell->mName = id; - if (cell.isExterior()) { - mExt.push_back(cell); - } else { - mInt.push_back(cell); + // The cell itself takes care of all the hairy details + cell->load(esm); + + if(cell->mData.mFlags & ESM::Cell::Interior) + { + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(id)); + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // have new cell replace old cell + *oldcell = *cell; + } else + mInt.push_back(*cell); + delete cell; + } + else + { + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); + std::cout << "setup - " << oldcell << " " << cell->getGridX() << " " << cell->getGridY() << std::endl; + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // have new cell replace old cell + *oldcell = *cell; + } else + mExt.push_back(*cell); + delete cell; } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1fa23700d..6dbba2a45 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -215,6 +215,8 @@ namespace MWWorld mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } + + mStore.setUp(); mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); mRendering->attachCameraTo(mPlayer->getPlayer()); diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index b7f27b08d..0158af70a 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -201,6 +201,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mRefnum &= 0x00ffffff; // delete old plugin ID const ESM::ESMReader::MasterList &masters = esm.getMasters(); global = masters[local-1].index + 1; + std::cout << "moved ref: " << local << " " << global << std::endl; ref.mRefnum |= global << 24; // insert global plugin ID } else From ef9575498f231e50a99a7beadc048e21ce74486d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 26 Nov 2012 12:29:22 +0100 Subject: [PATCH 029/916] basic (non-editable) subview for global variables --- apps/opencs/CMakeLists.txt | 9 +- apps/opencs/editor.cpp | 18 +++ apps/opencs/model/doc/document.cpp | 10 ++ apps/opencs/model/doc/document.hpp | 9 ++ apps/opencs/model/world/columns.hpp | 21 +++ apps/opencs/model/world/data.cpp | 47 +++++++ apps/opencs/model/world/data.hpp | 39 ++++++ apps/opencs/model/world/idcollection.cpp | 6 + apps/opencs/model/world/idcollection.hpp | 158 +++++++++++++++++++++++ apps/opencs/model/world/idtable.cpp | 55 ++++++++ apps/opencs/model/world/idtable.hpp | 37 ++++++ apps/opencs/model/world/record.hpp | 76 +++++++++++ apps/opencs/model/world/universalid.cpp | 29 ++++- apps/opencs/model/world/universalid.hpp | 7 +- apps/opencs/view/doc/view.cpp | 33 +++-- apps/opencs/view/doc/view.hpp | 11 +- apps/opencs/view/world/globals.cpp | 26 ++++ apps/opencs/view/world/globals.hpp | 17 +++ apps/opencs/view/world/subview.hpp | 22 ++++ components/esm/loadglob.hpp | 2 +- 20 files changed, 614 insertions(+), 18 deletions(-) create mode 100644 apps/opencs/model/world/columns.hpp create mode 100644 apps/opencs/model/world/data.cpp create mode 100644 apps/opencs/model/world/data.hpp create mode 100644 apps/opencs/model/world/idcollection.cpp create mode 100644 apps/opencs/model/world/idcollection.hpp create mode 100644 apps/opencs/model/world/idtable.cpp create mode 100644 apps/opencs/model/world/idtable.hpp create mode 100644 apps/opencs/model/world/record.hpp create mode 100644 apps/opencs/view/world/globals.cpp create mode 100644 apps/opencs/view/world/globals.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index a56e77d08..92fd859be 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -4,11 +4,11 @@ set (OPENCS_SRC model/doc/documentmanager.cpp model/doc/document.cpp - model/world/universalid.cpp + model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp - view/world/subview.cpp + view/world/subview.cpp view/world/globals.cpp ) set (OPENCS_HDR @@ -16,11 +16,12 @@ set (OPENCS_HDR model/doc/documentmanager.hpp model/doc/document.hpp - model/world/universalid.hpp + model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp + model/world/idtable.hpp model/world/columns.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp - view/world/subview.hpp + view/world/subview.hpp view/world/globals.hpp ) set (OPENCS_US diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index c03a1dc5d..6977a22f0 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -5,6 +5,9 @@ #include +#include "model/doc/document.hpp" +#include "model/world/data.hpp" + CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) { connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); @@ -17,6 +20,21 @@ void CS::Editor::createDocument() stream << "NewDocument" << (++mNewDocumentIndex); CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); + + static const char *sGlobals[] = + { + "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + }; + + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global record; + record.mId = sGlobals[i]; + record.mValue = i==0 ? 1 : 0; + record.mType = ESM::VT_Float; + document->getData().getGlobals().add (record); + } + mViewManager.addView (document); } diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index cd65e83ae..e8091b3e0 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -104,4 +104,14 @@ void CSMDoc::Document::verifying() mVerifyTimer.stop(); emit stateChanged (getState(), this); } +} + +const CSMWorld::Data& CSMDoc::Document::getData() const +{ + return mData; +} + +CSMWorld::Data& CSMDoc::Document::getData() +{ + return mData; } \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 1f73b5437..b414bf04d 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -7,6 +7,8 @@ #include #include +#include "../world/data.hpp" + namespace CSMDoc { class Document : public QObject @@ -25,8 +27,11 @@ namespace CSMDoc State_Searching = 32 // not implemented yet }; + private: + std::string mName; ///< \todo replace name with ESX list QUndoStack mUndoStack; + CSMWorld::Data mData; int mSaveCount; ///< dummy implementation -> remove when proper save is implemented. QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented. @@ -56,6 +61,10 @@ namespace CSMDoc void abortOperation (int type); + const CSMWorld::Data& getData() const; + + CSMWorld::Data& getData(); + signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp new file mode 100644 index 000000000..56362e4cd --- /dev/null +++ b/apps/opencs/model/world/columns.hpp @@ -0,0 +1,21 @@ +#ifndef CSM_WOLRD_COLUMNS_H +#define CSM_WOLRD_COLUMNS_H + +#include "idcollection.hpp" + +namespace CSMWorld +{ + template + struct FloatValueColumn : public Column + { + FloatValueColumn() : Column ("Value") {} + + virtual QVariant get (const Record& record) const + { + return record.get().mValue; + } + }; + +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp new file mode 100644 index 000000000..7fdb149b3 --- /dev/null +++ b/apps/opencs/model/world/data.cpp @@ -0,0 +1,47 @@ + +#include "data.hpp" + +#include + +#include + +#include + +#include "idtable.hpp" +#include "columns.hpp" + +CSMWorld::Data::Data() +{ + mGlobals.addColumn (new FloatValueColumn); + + mModels.insert (std::make_pair ( + UniversalId (UniversalId::Type_Globals), + new IdTable (&mGlobals) + )); +} + +CSMWorld::Data::~Data() +{ + for (std::map::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) + delete iter->second; +} + +const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const +{ + return mGlobals; +} + +CSMWorld::IdCollection& CSMWorld::Data::getGlobals() +{ + return mGlobals; +} + +QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) +{ + std::map::iterator iter = mModels.find (id); + + if (iter==mModels.end()) + throw std::logic_error ("No table model available for " + id.toString()); + + return iter->second; +} \ No newline at end of file diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp new file mode 100644 index 000000000..11073c5e3 --- /dev/null +++ b/apps/opencs/model/world/data.hpp @@ -0,0 +1,39 @@ +#ifndef CSM_WOLRD_IDLIST_H +#define CSM_WOLRD_IDLIST_H + +#include + +#include + +#include "idcollection.hpp" +#include "universalid.hpp" + +class QAbstractTableModel; + +namespace CSMWorld +{ + class Data + { + IdCollection mGlobals; + std::map mModels; + + // not implemented + Data (const Data&); + Data& operator= (const Data&); + + public: + + Data(); + + ~Data(); + + const IdCollection& getGlobals() const; + + IdCollection& getGlobals(); + + QAbstractTableModel *getTableModel (const UniversalId& id); + ///< If no table model is available for \æ id, an exception is thrown. + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp new file mode 100644 index 000000000..fc4bb1ef6 --- /dev/null +++ b/apps/opencs/model/world/idcollection.cpp @@ -0,0 +1,6 @@ + +#include "idcollection.hpp" + +CSMWorld::IdCollectionBase::IdCollectionBase() {} + +CSMWorld::IdCollectionBase::~IdCollectionBase() {} \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp new file mode 100644 index 000000000..0bddda1ac --- /dev/null +++ b/apps/opencs/model/world/idcollection.hpp @@ -0,0 +1,158 @@ +#ifndef CSM_WOLRD_IDCOLLECTION_H +#define CSM_WOLRD_IDCOLLECTION_H + +#include +#include +#include +#include +#include + +#include + +#include "record.hpp" + +namespace CSMWorld +{ + template + struct Column + { + std::string mTitle; + + Column (const std::string& title) : mTitle (title) {} + + virtual ~Column() {} + + virtual QVariant get (const Record& record) const = 0; + }; + + class IdCollectionBase + { + // not implemented + IdCollectionBase (const IdCollectionBase&); + IdCollectionBase& operator= (const IdCollectionBase&); + + public: + + IdCollectionBase(); + + virtual ~IdCollectionBase(); + + virtual int getSize() const = 0; + + virtual std::string getId (int index) const = 0; + + virtual int getColumns() const = 0; + + virtual std::string getTitle (int column) const = 0; + + virtual QVariant getData (int index, int column) const = 0; + }; + + ///< \brief Collection of ID-based records + template + class IdCollection : public IdCollectionBase + { + std::vector > mRecords; + std::map mIndex; + std::vector *> mColumns; + + // not implemented + IdCollection (const IdCollection&); + IdCollection& operator= (const IdCollection&); + + public: + + IdCollection(); + + virtual ~IdCollection(); + + void add (const ESXRecordT& record); + ///< Add a new record (modified) + + virtual int getSize() const; + + virtual std::string getId (int index) const; + + virtual int getColumns() const; + + virtual QVariant getData (int index, int column) const; + + virtual std::string getTitle (int column) const; + + virtual void addColumn (Column *column); + }; + + template + IdCollection::IdCollection() + {} + + template + IdCollection::~IdCollection() + { + for (typename std::vector *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) + delete *iter; + } + + template + void IdCollection::add (const ESXRecordT& record) + { + std::string id; + + std::transform (record.mId.begin(), record.mId.end(), std::back_inserter (id), + (int(*)(int)) std::tolower); + + std::map::iterator iter = mIndex.find (id); + + if (iter==mIndex.end()) + { + Record record2; + record2.mState = Record::State_ModifiedOnly; + record2.mModified = record; + + mRecords.push_back (record2); + mIndex.insert (std::make_pair (id, mRecords.size()-1)); + } + else + { + mRecords[iter->second].setModified (record); + } + } + + template + int IdCollection::getSize() const + { + return mRecords.size(); + } + + template + std::string IdCollection::getId (int index) const + { + return mRecords.at (index).get().mId; + } + + template + int IdCollection::getColumns() const + { + return mColumns.size(); + } + + template + QVariant IdCollection::getData (int index, int column) const + { + return mColumns.at (column)->get (mRecords.at (index)); + } + + template + std::string IdCollection::getTitle (int column) const + { + return mColumns.at (column)->mTitle; + } + + template + void IdCollection::addColumn (Column *column) + { + mColumns.push_back (column); + } +} + +#endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp new file mode 100644 index 000000000..f8acd4f9f --- /dev/null +++ b/apps/opencs/model/world/idtable.cpp @@ -0,0 +1,55 @@ + +#include "idtable.hpp" + +#include "idcollection.hpp" + +CSMWorld::IdTable::IdTable (IdCollectionBase *idCollection) : mIdCollection (idCollection) +{ + +} + +CSMWorld::IdTable::~IdTable() +{ + +} + +int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return mIdCollection->getSize(); +} + +int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return 1+mIdCollection->getColumns(); +} + +QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const +{ + if (role!=Qt::DisplayRole) + return QVariant(); + + if (index.column()==0) + return QVariant (tr (mIdCollection->getId (index.row()).c_str())); + + return mIdCollection->getData (index.row(), index.column()-1); +} + +QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const +{ + if (role!=Qt::DisplayRole) + return QVariant(); + + if (orientation==Qt::Vertical) + return QVariant(); + + if (section==0) + return QVariant (tr ("ID")); + + return tr (mIdCollection->getTitle (section-1).c_str()); +} \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp new file mode 100644 index 000000000..4fb939fa3 --- /dev/null +++ b/apps/opencs/model/world/idtable.hpp @@ -0,0 +1,37 @@ +#ifndef CSM_WOLRD_IDTABLE_H +#define CSM_WOLRD_IDTABLE_H + +#include + +namespace CSMWorld +{ + class IdCollectionBase; + + class IdTable : public QAbstractTableModel + { + Q_OBJECT + + IdCollectionBase *mIdCollection; + + // not implemented + IdTable (const IdTable&); + IdTable& operator= (const IdTable&); + + public: + + IdTable (IdCollectionBase *idCollection); + ///< The ownership of \a idCollection is not transferred. + + virtual ~IdTable(); + + int rowCount (const QModelIndex & parent = QModelIndex()) const; + + int columnCount (const QModelIndex & parent = QModelIndex()) const; + + QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + }; +} + +#endif diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp new file mode 100644 index 000000000..230d39eb0 --- /dev/null +++ b/apps/opencs/model/world/record.hpp @@ -0,0 +1,76 @@ +#ifndef CSM_WOLRD_RECORD_H +#define CSM_WOLRD_RECORD_H + +#include + +namespace CSMWorld +{ + template + struct Record + { + enum state + { + State_BaseOnly, // defined in base only + State_Modified, // exists in base, but has been modified + State_ModifiedOnly, // newly created in modified + State_Deleted // exists in base, but has been deleted + }; + + ESXRecordT mBase; + ESXRecordT mModified; + state mState; + + bool isDeleted() const; + + bool isModified() const; + + const ESXRecordT& get() const; + ///< Throws an exception, if the record is deleted. + + ESXRecordT& get(); + ///< Throws an exception, if the record is deleted. + + void setModified (const ESXRecordT& modified); + }; + + template + bool Record::isDeleted() const + { + return mState==State_Deleted; + } + + template + bool Record::isModified() const + { + return mState==State_Modified || mState==State_ModifiedOnly; + } + + template + const ESXRecordT& Record::get() const + { + if (isDeleted()) + throw std::logic_error ("attempt to access a deleted record"); + + return mState==State_BaseOnly ? mBase : mModified; + } + + template + ESXRecordT& Record::get() + { + if (isDeleted()) + throw std::logic_error ("attempt to access a deleted record"); + + return mState==State_BaseOnly ? mBase : mModified; + } + + template + void Record::setModified (const ESXRecordT& modified) + { + mModified = modified; + + if (mState!=State_ModifiedOnly) + mState = State_Modified; + } +} + +#endif diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index b56a336a6..e2d8d1ffb 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -17,6 +17,7 @@ namespace static const TypeData sNoArg[] = { { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -117,6 +118,23 @@ bool CSMWorld::UniversalId::isEqual (const UniversalId& universalId) const } } +bool CSMWorld::UniversalId::isLess (const UniversalId& universalId) const +{ + if (mTypeuniversalId.mType) + return false; + + switch (mArgumentType) + { + case ArgumentType_Id: return mId +#include #include #include @@ -10,6 +11,7 @@ #include "../../model/doc/document.hpp" #include "../world/subview.hpp" +#include "../world/globals.hpp" #include "viewmanager.hpp" #include "operations.hpp" @@ -59,16 +61,16 @@ void CSVDoc::View::setupViewMenu() QAction *newWindow = new QAction (tr ("&New View"), this); connect (newWindow, SIGNAL (triggered()), this, SLOT (newView())); view->addAction (newWindow); - - QAction *test = new QAction (tr ("Add test Subview"), this); - connect (test, SIGNAL (triggered()), this, SLOT (addTestSubView())); - view->addAction (test); } void CSVDoc::View::setupWorldMenu() { QMenu *world = menuBar()->addMenu (tr ("&World")); + QAction *globals = new QAction (tr ("Globals"), this); + connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView())); + world->addAction (globals); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -124,6 +126,16 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to updateTitle(); setupUi(); + + mSubViewFactories.insert (std::make_pair (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), + new CSVWorld::SubViewFactory())); +} + +CSVDoc::View::~View() +{ + for (std::map::iterator iter (mSubViewFactories.begin()); + iter!=mSubViewFactories.end(); ++iter) + delete iter->second; } const CSMDoc::Document *CSVDoc::View::getDocument() const @@ -176,8 +188,13 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) - CSVWorld::SubView *view = new CSVWorld::SubView (id); - addDockWidget (Qt::RightDockWidgetArea, view); + std::map::iterator iter = mSubViewFactories.find (id); + + if (iter==mSubViewFactories.end()) + throw std::logic_error ("can't create subview for " + id.toString()); + + CSVWorld::SubView *view = iter->second->makeSubView (id, mDocument->getData()); + addDockWidget (Qt::TopDockWidgetArea, view); view->show(); } @@ -201,7 +218,7 @@ void CSVDoc::View::verify() mDocument->verify(); } -void CSVDoc::View::addTestSubView() +void CSVDoc::View::addGlobalsSubView() { - addSubView (CSMWorld::UniversalId::Type_None); + addSubView (CSMWorld::UniversalId::Type_Globals); } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 7a9164e12..8e2b27293 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -2,6 +2,7 @@ #define CSV_DOC_VIEW_H #include +#include #include @@ -17,6 +18,11 @@ namespace CSMWorld class UniversalId; } +namespace CSVWorld +{ + struct SubViewFactoryBase; +} + namespace CSVDoc { class ViewManager; @@ -36,6 +42,7 @@ namespace CSVDoc QAction *mVerify; std::vector mEditingActions; Operations *mOperations; + std::map mSubViewFactories; // not implemented View (const View&); @@ -64,6 +71,8 @@ namespace CSVDoc View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); ///< The ownership of \a document is not transferred to *this. + virtual ~View(); + const CSMDoc::Document *getDocument() const; CSMDoc::Document *getDocument(); @@ -90,7 +99,7 @@ namespace CSVDoc void verify(); - void addTestSubView(); ///< \todo remove + void addGlobalsSubView(); }; } diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp new file mode 100644 index 000000000..1c0faa029 --- /dev/null +++ b/apps/opencs/view/world/globals.cpp @@ -0,0 +1,26 @@ + +#include "globals.hpp" + +#include +#include +#include + +#include "../../model/world/data.hpp" + +CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data) +: SubView (id) +{ + QTableView *table = new QTableView(); + + setWidget (table); + + QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel (this); + proxyModel->setSourceModel (data.getTableModel (id)); + + table->setModel (proxyModel); + table->horizontalHeader()->setResizeMode (QHeaderView::Interactive); + table->verticalHeader()->hide(); + table->setSortingEnabled (true); + + /// \todo make initial layout fill the whole width of the table +} \ No newline at end of file diff --git a/apps/opencs/view/world/globals.hpp b/apps/opencs/view/world/globals.hpp new file mode 100644 index 000000000..c54716255 --- /dev/null +++ b/apps/opencs/view/world/globals.hpp @@ -0,0 +1,17 @@ +#ifndef CSV_WORLD_GLOBALS_H +#define CSV_WORLD_GLOBALS_H + +#include "subview.hpp" + +namespace CSVWorld +{ + class Globals : public SubView + { + + public: + + Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subview.hpp b/apps/opencs/view/world/subview.hpp index 8488690c8..95cbe4243 100644 --- a/apps/opencs/view/world/subview.hpp +++ b/apps/opencs/view/world/subview.hpp @@ -5,6 +5,11 @@ #include +namespace CSMWorld +{ + class Data; +} + namespace CSVWorld { class SubView : public QDockWidget @@ -23,6 +28,23 @@ namespace CSVWorld CSMWorld::UniversalId getUniversalId() const; }; + + struct SubViewFactoryBase + { + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data) = 0; + }; + + template + struct SubViewFactory : public SubViewFactoryBase + { + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data); + }; + + template + SubView *SubViewFactory::makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data) + { + return new SubViewT (id, data); + } } #endif \ No newline at end of file diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 302729d2e..5cfb3c87b 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -18,7 +18,7 @@ class ESMWriter; struct Global { std::string mId; - unsigned mValue; + float mValue; VarType mType; void load(ESMReader &esm); From 92f70635a2bb7d26ffecd3582cfd6c18ae01516b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 27 Nov 2012 10:42:46 +0100 Subject: [PATCH 030/916] improved selection behaviour --- apps/opencs/view/world/globals.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp index 1c0faa029..1f68a57fe 100644 --- a/apps/opencs/view/world/globals.cpp +++ b/apps/opencs/view/world/globals.cpp @@ -21,6 +21,8 @@ CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& dat table->horizontalHeader()->setResizeMode (QHeaderView::Interactive); table->verticalHeader()->hide(); table->setSortingEnabled (true); + table->setSelectionBehavior (QAbstractItemView::SelectRows); + table->setSelectionMode (QAbstractItemView::ExtendedSelection); /// \todo make initial layout fill the whole width of the table } \ No newline at end of file From 8a09e03d5c6b369bffcac7dbb16916151eb2c548 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 Nov 2012 14:45:34 +0100 Subject: [PATCH 031/916] global variable editing (no undo support yet) --- apps/opencs/model/world/columns.hpp | 12 +++++++++ apps/opencs/model/world/idcollection.hpp | 26 ++++++++++++++++++- apps/opencs/model/world/idtable.cpp | 33 +++++++++++++++++++++++- apps/opencs/model/world/idtable.hpp | 4 +++ apps/opencs/model/world/record.hpp | 18 ++++++++----- components/esm/loadglob.cpp | 4 +++ components/esm/loadglob.hpp | 3 +++ 7 files changed, 91 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 56362e4cd..4d0ecb58e 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -14,6 +14,18 @@ namespace CSMWorld { return record.get().mValue; } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT base = record.getBase(); + base.mValue = data.toFloat(); + record.setModified (base); + } + + virtual bool isEditable() const + { + return true; + } }; } diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 0bddda1ac..ee6a4b2ce 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -23,6 +23,10 @@ namespace CSMWorld virtual ~Column() {} virtual QVariant get (const Record& record) const = 0; + + virtual void set (Record& record, const QVariant& data) = 0; + + virtual bool isEditable() const = 0; }; class IdCollectionBase @@ -46,6 +50,10 @@ namespace CSMWorld virtual std::string getTitle (int column) const = 0; virtual QVariant getData (int index, int column) const = 0; + + virtual void setData (int index, int column, const QVariant& data) = 0; + + virtual bool isEditable (int column) const = 0; }; ///< \brief Collection of ID-based records @@ -77,9 +85,13 @@ namespace CSMWorld virtual QVariant getData (int index, int column) const; + virtual void setData (int index, int column, const QVariant& data); + virtual std::string getTitle (int column) const; - virtual void addColumn (Column *column); + virtual bool isEditable (int column) const; + + void addColumn (Column *column); }; template @@ -142,12 +154,24 @@ namespace CSMWorld return mColumns.at (column)->get (mRecords.at (index)); } + template + void IdCollection::setData (int index, int column, const QVariant& data) + { + return mColumns.at (column)->set (mRecords.at (index), data); + } + template std::string IdCollection::getTitle (int column) const { return mColumns.at (column)->mTitle; } + template + bool IdCollection::isEditable (int column) const + { + return mColumns.at (column)->isEditable(); + } + template void IdCollection::addColumn (Column *column) { diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index f8acd4f9f..8fdc4fb8f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -31,9 +31,18 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const { - if (role!=Qt::DisplayRole) + if (role!=Qt::DisplayRole && role!=Qt::EditRole) return QVariant(); + if (role==Qt::EditRole) + { + if (index.column()==0) + return QVariant(); + + if (!mIdCollection->isEditable (index.column()-1)) + return QVariant(); + } + if (index.column()==0) return QVariant (tr (mIdCollection->getId (index.row()).c_str())); @@ -52,4 +61,26 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation return QVariant (tr ("ID")); return tr (mIdCollection->getTitle (section-1).c_str()); +} + +bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role) +{ + if (index.column()>0 && role==Qt::EditRole) + { + mIdCollection->setData (index.row(), index.column()-1, value); + emit dataChanged (index, index); + return true; + } + + return false; +} + +Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const +{ + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if (index.column()>0) + flags |= Qt::ItemIsEditable; + + return flags; } \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 4fb939fa3..30af3aaf7 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -31,6 +31,10 @@ namespace CSMWorld QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + Qt::ItemFlags flags (const QModelIndex & index) const; }; } diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 230d39eb0..950d7f176 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -8,7 +8,7 @@ namespace CSMWorld template struct Record { - enum state + enum State { State_BaseOnly, // defined in base only State_Modified, // exists in base, but has been modified @@ -18,7 +18,7 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; - state mState; + State mState; bool isDeleted() const; @@ -27,10 +27,11 @@ namespace CSMWorld const ESXRecordT& get() const; ///< Throws an exception, if the record is deleted. - ESXRecordT& get(); - ///< Throws an exception, if the record is deleted. + const ESXRecordT& getBase() const; + ///< Throws an exception, if the record is deleted. Returns modified, if there is no base. void setModified (const ESXRecordT& modified); + ///< Throws an exception, if the record is deleted. }; template @@ -55,21 +56,24 @@ namespace CSMWorld } template - ESXRecordT& Record::get() + const ESXRecordT& Record::getBase() const { if (isDeleted()) throw std::logic_error ("attempt to access a deleted record"); - return mState==State_BaseOnly ? mBase : mModified; + return mState==State_ModifiedOnly ? mModified : mBase; } template void Record::setModified (const ESXRecordT& modified) { + if (isDeleted()) + throw std::logic_error ("attempt to modify a deleted record"); + mModified = modified; if (mState!=State_ModifiedOnly) - mState = State_Modified; + mState = mBase==mModified ? State_BaseOnly : State_Modified; } } diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 39c07fb31..0335da0df 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -44,4 +44,8 @@ void Global::save(ESMWriter &esm) esm.writeHNT("FLTV", mValue); } + bool operator== (const Global& left, const Global& right) + { + return left.mId==right.mId && left.mValue==right.mValue && left.mType==right.mType; + } } diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 5cfb3c87b..5c5dafaec 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -24,5 +24,8 @@ struct Global void load(ESMReader &esm); void save(ESMWriter &esm); }; + +bool operator== (const Global& left, const Global& right); + } #endif From 4086b556d242280d7ad2e8bd030e7118dab5d57d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 Nov 2012 16:05:28 +0100 Subject: [PATCH 032/916] use commands for modifying globals --- apps/opencs/CMakeLists.txt | 2 + apps/opencs/model/world/commands.cpp | 23 +++++++++++ apps/opencs/model/world/commands.hpp | 33 ++++++++++++++++ apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/world/globals.cpp | 59 +++++++++++++++++++++++++++- apps/opencs/view/world/globals.hpp | 42 +++++++++++++++++++- apps/opencs/view/world/subview.hpp | 12 ++++-- 7 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 apps/opencs/model/world/commands.cpp create mode 100644 apps/opencs/model/world/commands.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 92fd859be..61580461f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -5,6 +5,7 @@ set (OPENCS_SRC model/doc/documentmanager.cpp model/doc/document.cpp model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp + model/world/commands.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp @@ -20,6 +21,7 @@ set (OPENCS_HDR model/world/idtable.hpp model/world/columns.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp + model/world/commands.hpp view/world/subview.hpp view/world/globals.hpp ) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp new file mode 100644 index 000000000..a15d00619 --- /dev/null +++ b/apps/opencs/model/world/commands.cpp @@ -0,0 +1,23 @@ + +#include "commands.hpp" + +#include + +CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, + const QVariant& new_, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) +{ + mOld = mModel.data (mIndex, Qt::EditRole); + + setText ("Modify " + mModel.headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); +} + +void CSMWorld::ModifyCommand::redo() +{ + mModel.setData (mIndex, mNew); +} + +void CSMWorld::ModifyCommand::undo() +{ + mModel.setData (mIndex, mOld); +} \ No newline at end of file diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp new file mode 100644 index 000000000..ffaee59ef --- /dev/null +++ b/apps/opencs/model/world/commands.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_WOLRD_COMMANDS_H +#define CSM_WOLRD_COMMANDS_H + +#include "record.hpp" + +#include +#include +#include + +class QModelIndex; +class QAbstractItemModel; + +namespace CSMWorld +{ + class ModifyCommand : public QUndoCommand + { + QAbstractItemModel& mModel; + QModelIndex mIndex; + QVariant mNew; + QVariant mOld; + + public: + + ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, + QUndoCommand *parent = 0); + + virtual void redo(); + + virtual void undo(); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 18d58bbf5..c81ba2ba1 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -193,7 +193,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) if (iter==mSubViewFactories.end()) throw std::logic_error ("can't create subview for " + id.toString()); - CSVWorld::SubView *view = iter->second->makeSubView (id, mDocument->getData()); + CSVWorld::SubView *view = iter->second->makeSubView (id, mDocument->getData(), mDocument->getUndoStack()); addDockWidget (Qt::TopDockWidgetArea, view); view->show(); } diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp index 1f68a57fe..a57f63dff 100644 --- a/apps/opencs/view/world/globals.cpp +++ b/apps/opencs/view/world/globals.cpp @@ -4,18 +4,73 @@ #include #include #include +#include #include "../../model/world/data.hpp" -CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data) +#include "../../model/world/commands.hpp" + +CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) +: mModel (model) +{} + +int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const +{ + return mModel.rowCount (parent); +} + +int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const +{ + return mModel.columnCount (parent); +} + +QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const +{ + return mModel.data (index, role); +} + +bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role) +{ + mData = value; + return true; +} + +QVariant CSVWorld::NastyTableModelHack::getData() const +{ + return mData; +} + +CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) +: QStyledItemDelegate (parent), mUndoStack (undoStack) +{} + +void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); +} + +CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) : SubView (id) { QTableView *table = new QTableView(); setWidget (table); + QAbstractTableModel *model = data.getTableModel (id); + + int columns = model->columnCount(); + + for (int i=1; isetItemDelegateForColumn (i, delegate); + } + QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel (this); - proxyModel->setSourceModel (data.getTableModel (id)); + proxyModel->setSourceModel (model); table->setModel (proxyModel); table->horizontalHeader()->setResizeMode (QHeaderView::Interactive); diff --git a/apps/opencs/view/world/globals.hpp b/apps/opencs/view/world/globals.hpp index c54716255..11ab7b6aa 100644 --- a/apps/opencs/view/world/globals.hpp +++ b/apps/opencs/view/world/globals.hpp @@ -3,14 +3,52 @@ #include "subview.hpp" +#include + +class QUndoStack; + namespace CSVWorld { - class Globals : public SubView + ///< \brief Getting the data out of an editor widget + /// + /// Really, Qt? Really? + class NastyTableModelHack : public QAbstractTableModel { + QAbstractItemModel& mModel; + QVariant mData; public: - Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data); + NastyTableModelHack (QAbstractItemModel& model); + + int rowCount (const QModelIndex & parent = QModelIndex()) const; + + int columnCount (const QModelIndex & parent = QModelIndex()) const; + + QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + QVariant getData() const; + }; + + ///< \brief Use commands instead of manipulating the model directly + class CommandDelegate : public QStyledItemDelegate + { + QUndoStack& mUndoStack; + + public: + + CommandDelegate (QUndoStack& undoStack, QObject *parent); + + void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + }; + + class Globals : public SubView + { + public: + + Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); }; } diff --git a/apps/opencs/view/world/subview.hpp b/apps/opencs/view/world/subview.hpp index 95cbe4243..fd7a51631 100644 --- a/apps/opencs/view/world/subview.hpp +++ b/apps/opencs/view/world/subview.hpp @@ -5,6 +5,8 @@ #include +class QUndoStack; + namespace CSMWorld { class Data; @@ -31,19 +33,21 @@ namespace CSVWorld struct SubViewFactoryBase { - virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data) = 0; + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) + = 0; }; template struct SubViewFactory : public SubViewFactoryBase { - virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data); + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); }; template - SubView *SubViewFactory::makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data) + SubView *SubViewFactory::makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, + QUndoStack& undoStack) { - return new SubViewT (id, data); + return new SubViewT (id, data, undoStack); } } From fd55c0cae2603562c7a648bf62c70bbbd33976a3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 Nov 2012 18:56:28 +0100 Subject: [PATCH 033/916] record IDs are no longer handled as a special case --- apps/opencs/model/world/columns.hpp | 16 +++++++++++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/model/world/idcollection.hpp | 6 +++++- apps/opencs/model/world/idtable.cpp | 26 +++++++----------------- apps/opencs/view/world/globals.cpp | 2 +- 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 4d0ecb58e..3220b3bba 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -28,6 +28,22 @@ namespace CSMWorld } }; + template + struct StringIdColumn : public Column + { + StringIdColumn() : Column ("ID") {} + + virtual QVariant get (const Record& record) const + { + return record.get().mId.c_str(); + } + + virtual bool isEditable() const + { + return false; + } + }; + } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 7fdb149b3..aeafc1676 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -12,6 +12,7 @@ CSMWorld::Data::Data() { + mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new FloatValueColumn); mModels.insert (std::make_pair ( diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index ee6a4b2ce..41cd352ce 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -24,7 +25,10 @@ namespace CSMWorld virtual QVariant get (const Record& record) const = 0; - virtual void set (Record& record, const QVariant& data) = 0; + virtual void set (Record& record, const QVariant& data) + { + throw std::logic_error ("Column " + mTitle + " is not editable"); + } virtual bool isEditable() const = 0; }; diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 8fdc4fb8f..1fc2bfedb 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -26,7 +26,7 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 1+mIdCollection->getColumns(); + return mIdCollection->getColumns(); } QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const @@ -34,19 +34,10 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role!=Qt::DisplayRole && role!=Qt::EditRole) return QVariant(); - if (role==Qt::EditRole) - { - if (index.column()==0) + if (role==Qt::EditRole && !mIdCollection->isEditable (index.column())) return QVariant(); - if (!mIdCollection->isEditable (index.column()-1)) - return QVariant(); - } - - if (index.column()==0) - return QVariant (tr (mIdCollection->getId (index.row()).c_str())); - - return mIdCollection->getData (index.row(), index.column()-1); + return mIdCollection->getData (index.row(), index.column()); } QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const @@ -57,17 +48,14 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation if (orientation==Qt::Vertical) return QVariant(); - if (section==0) - return QVariant (tr ("ID")); - - return tr (mIdCollection->getTitle (section-1).c_str()); + return tr (mIdCollection->getTitle (section).c_str()); } bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role) { - if (index.column()>0 && role==Qt::EditRole) + if (mIdCollection->isEditable (index.column()) && role==Qt::EditRole) { - mIdCollection->setData (index.row(), index.column()-1, value); + mIdCollection->setData (index.row(), index.column(), value); emit dataChanged (index, index); return true; } @@ -79,7 +67,7 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - if (index.column()>0) + if (mIdCollection->isEditable (index.column())) flags |= Qt::ItemIsEditable; return flags; diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp index a57f63dff..459b8c357 100644 --- a/apps/opencs/view/world/globals.cpp +++ b/apps/opencs/view/world/globals.cpp @@ -63,7 +63,7 @@ CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& dat int columns = model->columnCount(); - for (int i=1; isetItemDelegateForColumn (i, delegate); From 8dd76b49af58ee7822fd11145cf0694a11ca51b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 29 Nov 2012 19:09:06 +0100 Subject: [PATCH 034/916] factored out table widget from globals sub view --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/view/doc/view.cpp | 11 --- apps/opencs/view/doc/view.hpp | 2 - apps/opencs/view/world/globals.cpp | 75 +----------------- apps/opencs/view/world/globals.hpp | 37 --------- apps/opencs/view/world/table.cpp | 118 +++++++++++++++++++++++++++++ apps/opencs/view/world/table.hpp | 25 ++++++ 7 files changed, 147 insertions(+), 125 deletions(-) create mode 100644 apps/opencs/view/world/table.cpp create mode 100644 apps/opencs/view/world/table.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 61580461f..dfd987345 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -9,7 +9,7 @@ set (OPENCS_SRC view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp - view/world/subview.cpp view/world/globals.cpp + view/world/subview.cpp view/world/table.cpp view/world/globals.cpp ) set (OPENCS_HDR @@ -23,7 +23,7 @@ set (OPENCS_HDR view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp model/world/commands.hpp - view/world/subview.hpp view/world/globals.hpp + view/world/subview.hpp view/world/table.hpp view/world/globals.hpp ) set (OPENCS_US diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index c81ba2ba1..0c336376b 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -46,12 +46,6 @@ void CSVDoc::View::setupEditMenu() mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo")); mRedo->setShortcuts (QKeySequence::Redo); edit->addAction (mRedo); - - // test - QAction *test = new QAction (tr ("&Test Command"), this); - connect (test, SIGNAL (triggered()), this, SLOT (test())); - edit->addAction (test); - mEditingActions.push_back (test); } void CSVDoc::View::setupViewMenu() @@ -203,11 +197,6 @@ void CSVDoc::View::newView() mViewManager.addView (mDocument); } -void CSVDoc::View::test() -{ - mDocument->getUndoStack().push (new QUndoCommand()); -} - void CSVDoc::View::save() { mDocument->save(); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 8e2b27293..c86c3b362 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -93,8 +93,6 @@ namespace CSVDoc void newView(); - void test(); - void save(); void verify(); diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp index 459b8c357..a8b6497db 100644 --- a/apps/opencs/view/world/globals.cpp +++ b/apps/opencs/view/world/globals.cpp @@ -1,83 +1,12 @@ #include "globals.hpp" -#include -#include -#include -#include - -#include "../../model/world/data.hpp" - -#include "../../model/world/commands.hpp" - -CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) -: mModel (model) -{} - -int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const -{ - return mModel.rowCount (parent); -} - -int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const -{ - return mModel.columnCount (parent); -} - -QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const -{ - return mModel.data (index, role); -} - -bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role) -{ - mData = value; - return true; -} - -QVariant CSVWorld::NastyTableModelHack::getData() const -{ - return mData; -} - -CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) -: QStyledItemDelegate (parent), mUndoStack (undoStack) -{} - -void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, - const QModelIndex& index) const -{ - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); -} +#include "table.hpp" CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) : SubView (id) { - QTableView *table = new QTableView(); + QTableView *table = new Table (id, data, undoStack); setWidget (table); - - QAbstractTableModel *model = data.getTableModel (id); - - int columns = model->columnCount(); - - for (int i=0; isetItemDelegateForColumn (i, delegate); - } - - QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel (this); - proxyModel->setSourceModel (model); - - table->setModel (proxyModel); - table->horizontalHeader()->setResizeMode (QHeaderView::Interactive); - table->verticalHeader()->hide(); - table->setSortingEnabled (true); - table->setSelectionBehavior (QAbstractItemView::SelectRows); - table->setSelectionMode (QAbstractItemView::ExtendedSelection); - - /// \todo make initial layout fill the whole width of the table } \ No newline at end of file diff --git a/apps/opencs/view/world/globals.hpp b/apps/opencs/view/world/globals.hpp index 11ab7b6aa..c4a9fd402 100644 --- a/apps/opencs/view/world/globals.hpp +++ b/apps/opencs/view/world/globals.hpp @@ -3,47 +3,10 @@ #include "subview.hpp" -#include - class QUndoStack; namespace CSVWorld { - ///< \brief Getting the data out of an editor widget - /// - /// Really, Qt? Really? - class NastyTableModelHack : public QAbstractTableModel - { - QAbstractItemModel& mModel; - QVariant mData; - - public: - - NastyTableModelHack (QAbstractItemModel& model); - - int rowCount (const QModelIndex & parent = QModelIndex()) const; - - int columnCount (const QModelIndex & parent = QModelIndex()) const; - - QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - - bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - - QVariant getData() const; - }; - - ///< \brief Use commands instead of manipulating the model directly - class CommandDelegate : public QStyledItemDelegate - { - QUndoStack& mUndoStack; - - public: - - CommandDelegate (QUndoStack& undoStack, QObject *parent); - - void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; - }; - class Globals : public SubView { public: diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp new file mode 100644 index 000000000..2c9aa431f --- /dev/null +++ b/apps/opencs/view/world/table.cpp @@ -0,0 +1,118 @@ + +#include "table.hpp" + +#include +#include +#include +#include + +#include "../../model/world/data.hpp" + +#include "../../model/world/commands.hpp" + +namespace CSVWorld +{ + ///< \brief Getting the data out of an editor widget + /// + /// Really, Qt? Really? + class NastyTableModelHack : public QAbstractTableModel + { + QAbstractItemModel& mModel; + QVariant mData; + + public: + + NastyTableModelHack (QAbstractItemModel& model); + + int rowCount (const QModelIndex & parent = QModelIndex()) const; + + int columnCount (const QModelIndex & parent = QModelIndex()) const; + + QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + QVariant getData() const; + }; + + ///< \brief Use commands instead of manipulating the model directly + class CommandDelegate : public QStyledItemDelegate + { + QUndoStack& mUndoStack; + + public: + + CommandDelegate (QUndoStack& undoStack, QObject *parent); + + void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + }; + +} + +CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) +: mModel (model) +{} + +int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const +{ + return mModel.rowCount (parent); +} + +int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const +{ + return mModel.columnCount (parent); +} + +QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const +{ + return mModel.data (index, role); +} + +bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role) +{ + mData = value; + return true; +} + +QVariant CSVWorld::NastyTableModelHack::getData() const +{ + return mData; +} + +CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) +: QStyledItemDelegate (parent), mUndoStack (undoStack) +{} + +void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); +} + + +CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) +{ + QAbstractTableModel *model = data.getTableModel (id); + + int columns = model->columnCount(); + + for (int i=0; isetSourceModel (model); + + setModel (proxyModel); + horizontalHeader()->setResizeMode (QHeaderView::Interactive); + verticalHeader()->hide(); + setSortingEnabled (true); + setSelectionBehavior (QAbstractItemView::SelectRows); + setSelectionMode (QAbstractItemView::ExtendedSelection); + + /// \todo make initial layout fill the whole width of the table +} \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp new file mode 100644 index 000000000..dbb3c3443 --- /dev/null +++ b/apps/opencs/view/world/table.hpp @@ -0,0 +1,25 @@ +#ifndef CSV_WORLD_TABLE_H +#define CSV_WORLD_TABLE_H + +#include + +class QUndoStack; + +namespace CSMWorld +{ + class Data; + class UniversalId; +} + +namespace CSVWorld +{ + ///< Table widget + class Table : public QTableView + { + public: + + Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); + }; +} + +#endif From 7079b9062f66250fa9b0790c75bfd76533cbd814 Mon Sep 17 00:00:00 2001 From: rpopovici Date: Fri, 30 Nov 2012 02:16:16 +0200 Subject: [PATCH 035/916] add AI script functions --- apps/openmw/mwmechanics/aiescort.cpp | 6 + apps/openmw/mwmechanics/aiescort.hpp | 5 + apps/openmw/mwmechanics/aifollow.cpp | 5 + apps/openmw/mwmechanics/aifollow.hpp | 4 +- apps/openmw/mwscript/aiextensions.cpp | 239 +++++++++++++++++++++++-- apps/openmw/mwscript/docs/vmformat.txt | 16 +- 6 files changed, 262 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 27cd9095d..ebbea55b0 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -5,6 +5,12 @@ MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x : mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration) { } + +MWMechanics::AiEscort::AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z) +: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration) +{ +} + MWMechanics::AiEscort *MWMechanics::AiEscort::clone() const { diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index fef70f508..d89a9586c 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -10,6 +10,10 @@ namespace MWMechanics { public: AiEscort(const std::string &actorId,int duration, float x, float y, float z); + ///< \implement AiEscort + AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z); + ///< \implement AiEscortCell + virtual AiEscort *clone() const; virtual bool execute (const MWWorld::Ptr& actor); @@ -19,6 +23,7 @@ namespace MWMechanics private: std::string mActorId; + std::string mCellId; float mX; float mY; float mZ; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 3fee6d98c..dab9e0283 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -5,6 +5,11 @@ MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float : mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId) { } +MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z) +: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId) +{ +} + MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const { return new AiFollow(*this); diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index ded13d780..0b37b0a2d 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -11,6 +11,7 @@ namespace MWMechanics { public: AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z); + AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z); virtual AiFollow *clone() const; virtual bool execute (const MWWorld::Ptr& actor); ///< \return Package completed? @@ -21,7 +22,8 @@ namespace MWMechanics float mX; float mY; float mZ; - std::string mActorId; + std::string mActorId; + std::string mCellId; }; } #endif diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 787962ad1..a4108c17e 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -10,6 +10,11 @@ #include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/aiactivate.hpp" +#include "../mwmechanics/aiescort.hpp" +#include "../mwmechanics/aifollow.hpp" +#include "../mwmechanics/aitravel.hpp" +#include "../mwmechanics/aiwander.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -20,6 +25,27 @@ namespace MWScript { namespace Ai { + template + class OpAiActivate : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string objectID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i class OpAiTravel : public Interpreter::Opcode1 { @@ -41,6 +67,9 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i + class OpAiEscortCell : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string cellID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float duration = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i idleList; + for (unsigned int i=0; i + class OpAiFollow : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float duration = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i + class OpAiFollowCell : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string cellID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float duration = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + + // discard additional arguments (reset), because we have no idea what they mean. + for (unsigned int i=0; i + class OpGetCurrentAIPackage : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().getTypeId (); + + runtime.push (value); + } + }; + + template + class OpGetDetected : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer value = false; // TODO replace with implementation + + std::cout << "AiGetDetected: " << actorID << ", " << value << std::endl; + + runtime.push (value); + } + }; + const int opcodeAiTravel = 0x20000; const int opcodeAiTravelExplicit = 0x20001; @@ -189,8 +375,20 @@ namespace MWScript const int opcodeAiEscortExplicit = 0x20003; const int opcodeGetAiPackageDone = 0x200007c; const int opcodeGetAiPackageDoneExplicit = 0x200007d; + const int opcodeGetCurrentAiPackage = 0x20001b1; + const int opcodeGetCurrentAiPackageExplicit = 0x20001b2; + const int opcodeGetDetected = 0x20001b3; + const int opcodeGetDetectedExplicit = 0x20001b4; const int opcodeAiWander = 0x20010; const int opcodeAiWanderExplicit = 0x20011; + const int opcodeAIActivate = 0x20018; + const int opcodeAIActivateExplicit = 0x20019; + const int opcodeAiEscortCell = 0x2001a; + const int opcodeAiEscortCellExplicit = 0x2001b; + const int opcodeAiFollow = 0x2001c; + const int opcodeAiFollowExplicit = 0x2001d; + const int opcodeAiFollowCell = 0x2001e; + const int opcodeAiFollowCellExplicit = 0x2001f; const int opcodeSetHello = 0x200015e; const int opcodeSetHelloExplicit = 0x200015d; const int opcodeSetFight = 0x200015e; @@ -202,16 +400,26 @@ namespace MWScript void registerExtensions (Compiler::Extensions& extensions) { + extensions.registerInstruction ("aiactivate", "c/l", opcodeAIActivate, + opcodeAIActivateExplicit); extensions.registerInstruction ("aitravel", "fff/l", opcodeAiTravel, opcodeAiTravelExplicit); extensions.registerInstruction ("aiescort", "cffff/l", opcodeAiEscort, opcodeAiEscortExplicit); + extensions.registerInstruction ("aiescortcell", "ccffff/l", opcodeAiEscortCell, + opcodeAiEscortCellExplicit); extensions.registerInstruction ("aiwander", "fff/llllllllll", opcodeAiWander, opcodeAiWanderExplicit); - + extensions.registerInstruction ("aifollow", "cffff/l", opcodeAiFollow, + opcodeAiFollowExplicit); + extensions.registerInstruction ("aifollowcell", "ccffff/l", opcodeAiFollowCell, + opcodeAiFollowCellExplicit); extensions.registerFunction ("getaipackagedone", 'l', "", opcodeGetAiPackageDone, opcodeGetAiPackageDoneExplicit); - + extensions.registerFunction ("getcurrentaipackage", 'l', "", opcodeGetCurrentAiPackage, + opcodeGetAiPackageDoneExplicit); + extensions.registerFunction ("getdetected", 'l', "c", opcodeGetDetected, + opcodeGetDetectedExplicit); extensions.registerInstruction ("sethello", "l", opcodeSetHello, opcodeSetHelloExplicit); extensions.registerInstruction ("setfight", "l", opcodeSetFight, opcodeSetFightExplicit); extensions.registerInstruction ("setflee", "l", opcodeSetFlee, opcodeSetFleeExplicit); @@ -220,15 +428,26 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { + interpreter.installSegment3 (opcodeAIActivate, new OpAiActivate); + interpreter.installSegment3 (opcodeAIActivateExplicit, new OpAiActivate); interpreter.installSegment3 (opcodeAiTravel, new OpAiTravel); interpreter.installSegment3 (opcodeAiTravelExplicit, new OpAiTravel); interpreter.installSegment3 (opcodeAiEscort, new OpAiEscort); interpreter.installSegment3 (opcodeAiEscortExplicit, new OpAiEscort); + interpreter.installSegment3 (opcodeAiEscortCell, new OpAiEscortCell); + interpreter.installSegment3 (opcodeAiEscortCellExplicit, new OpAiEscortCell); interpreter.installSegment3 (opcodeAiWander, new OpAiWander); interpreter.installSegment3 (opcodeAiWanderExplicit, new OpAiWander); + interpreter.installSegment3 (opcodeAiFollow, new OpAiFollow); + interpreter.installSegment3 (opcodeAiFollowExplicit, new OpAiFollow); + interpreter.installSegment3 (opcodeAiFollowCell, new OpAiFollowCell); + interpreter.installSegment3 (opcodeAiFollowCellExplicit, new OpAiFollowCell); interpreter.installSegment5 (opcodeGetAiPackageDone, new OpGetAiPackageDone); - interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, - new OpGetAiPackageDone); + interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDone); + interpreter.installSegment5 (opcodeGetCurrentAiPackage, new OpGetCurrentAIPackage); + interpreter.installSegment5 (opcodeGetCurrentAiPackageExplicit, new OpGetCurrentAIPackage); + interpreter.installSegment3 (opcodeGetDetected, new OpGetDetected); + interpreter.installSegment3 (opcodeGetDetectedExplicit, new OpGetDetected); interpreter.installSegment5 (opcodeSetHello, new OpSetHello); interpreter.installSegment5 (opcodeSetHelloExplicit, new OpSetHello); interpreter.installSegment5 (opcodeSetFight, new OpSetFight); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index b130aa954..19517ac8d 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -37,7 +37,15 @@ op 0x20014: SetPCFacRep op 0x20015: SetPCFacRep, explicit reference op 0x20016: ModPCFacRep op 0x20017: ModPCFacRep, explicit reference -op s 0x20018-0x3ffff unused +op 0x20018: AIActivate +op 0x20019: AIActivate, explicit reference +op 0x2001a: AiEscortCell +op 0x2001b: AiEscortCell, explicit reference +op 0x2001c: AiFollow +op 0x2001d: AiFollow, explicit reference +op 0x2001e: AiFollowCell +op 0x2001f: AiFollowCell, explicit reference +op s 0x20020-0x3ffff unused Segment 4: (not implemented yet) @@ -226,5 +234,9 @@ op 0x20001ad: SetReputation op 0x20001ae: ModReputation op 0x20001af: SetReputation, explicit op 0x20001b0: ModReputation, explicit -opcodes 0x20001b1-0x3ffffff unused +op 0x20001b1: GetCurrentAIPackage +op 0x20001b2: GetCurrentAIPackage, explicit reference +op 0x20001b3: GetDetected +op 0x20001b4: GetDetected, explicit reference +opcodes 0x20001b5-0x3ffffff unused From ec1f957e54887dcb153d4ab07c51348373f65bb7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 30 Nov 2012 13:58:10 +0100 Subject: [PATCH 036/916] edit lock for sub views --- apps/opencs/view/doc/view.cpp | 5 +++++ apps/opencs/view/world/globals.cpp | 7 +++++-- apps/opencs/view/world/globals.hpp | 6 ++++++ apps/opencs/view/world/subview.hpp | 2 ++ apps/opencs/view/world/table.cpp | 27 +++++++++++++++++++++++---- apps/opencs/view/world/table.hpp | 8 ++++++++ 6 files changed, 49 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 0c336376b..3d5ebc84b 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -165,6 +165,11 @@ void CSVDoc::View::updateDocumentState() for (int i=0; operations[i]!=-1; ++i) if (!(state & operations[i])) mOperations->quitOperation (operations[i]); + + QList subViews = findChildren(); + + for (QList::iterator iter (subViews.begin()); iter!=subViews.end(); ++iter) + (*iter)->setEditLock (state && CSMDoc::Document::State_Locked); } void CSVDoc::View::updateProgress (int current, int max, int type, int threads) diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp index a8b6497db..68c9012aa 100644 --- a/apps/opencs/view/world/globals.cpp +++ b/apps/opencs/view/world/globals.cpp @@ -6,7 +6,10 @@ CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) : SubView (id) { - QTableView *table = new Table (id, data, undoStack); + setWidget (mTable = new Table (id, data, undoStack)); +} - setWidget (table); +void CSVWorld::Globals::setEditLock (bool locked) +{ + mTable->setEditLock (locked); } \ No newline at end of file diff --git a/apps/opencs/view/world/globals.hpp b/apps/opencs/view/world/globals.hpp index c4a9fd402..33cbce47f 100644 --- a/apps/opencs/view/world/globals.hpp +++ b/apps/opencs/view/world/globals.hpp @@ -7,11 +7,17 @@ class QUndoStack; namespace CSVWorld { + class Table; + class Globals : public SubView { + Table *mTable; + public: Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); + + virtual void setEditLock (bool locked); }; } diff --git a/apps/opencs/view/world/subview.hpp b/apps/opencs/view/world/subview.hpp index fd7a51631..543a9b2a1 100644 --- a/apps/opencs/view/world/subview.hpp +++ b/apps/opencs/view/world/subview.hpp @@ -29,6 +29,8 @@ namespace CSVWorld SubView (const CSMWorld::UniversalId& id); CSMWorld::UniversalId getUniversalId() const; + + virtual void setEditLock (bool locked) = 0; }; struct SubViewFactoryBase diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 2c9aa431f..590f7ea98 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -39,12 +39,15 @@ namespace CSVWorld class CommandDelegate : public QStyledItemDelegate { QUndoStack& mUndoStack; + bool mEditLock; public: CommandDelegate (QUndoStack& undoStack, QObject *parent); void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + + void setEditLock (bool locked); }; } @@ -80,15 +83,24 @@ QVariant CSVWorld::NastyTableModelHack::getData() const } CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) -: QStyledItemDelegate (parent), mUndoStack (undoStack) +: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) {} void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const { - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + if (!mEditLock) + { + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + } + ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. +} + +void CSVWorld::CommandDelegate::setEditLock (bool locked) +{ + mEditLock = locked; } @@ -101,6 +113,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q for (int i=0; i::iterator iter (mDelegates.begin()); iter!=mDelegates.end(); ++iter) + (*iter)->setEditLock (locked); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index dbb3c3443..ae203f516 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_TABLE_H #define CSV_WORLD_TABLE_H +#include + #include class QUndoStack; @@ -13,12 +15,18 @@ namespace CSMWorld namespace CSVWorld { + class CommandDelegate; + ///< Table widget class Table : public QTableView { + std::vector mDelegates; + public: Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); + + void setEditLock (bool locked); }; } From bd5e364ac1e29667e789d026360170f8a66734dc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 1 Dec 2012 13:42:12 +0100 Subject: [PATCH 037/916] display record state in table --- apps/opencs/model/world/columns.hpp | 15 +++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 16 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 3220b3bba..e81780cee 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -44,6 +44,21 @@ namespace CSMWorld } }; + template + struct RecordStateColumn : public Column + { + RecordStateColumn() : Column ("*") {} + + virtual QVariant get (const Record& record) const + { + return static_cast (record.mState); + } + + virtual bool isEditable() const + { + return false; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index aeafc1676..c0df54c10 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -13,6 +13,7 @@ CSMWorld::Data::Data() { mGlobals.addColumn (new StringIdColumn); + mGlobals.addColumn (new RecordStateColumn); mGlobals.addColumn (new FloatValueColumn); mModels.insert (std::make_pair ( From d432420a324843b47a04bd181efa88d56544d98c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 1 Dec 2012 20:53:28 +0100 Subject: [PATCH 038/916] fix FindFFmpeg.cmake --- CMakeLists.txt | 5 +- apps/openmw/mwsound/ffmpeg_decoder.hpp | 4 +- cmake/FindFFMPEG.cmake | 105 ------------------ cmake/FindFFmpeg.cmake | 148 +++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 109 deletions(-) delete mode 100644 cmake/FindFFMPEG.cmake create mode 100644 cmake/FindFFmpeg.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 78388e20f..fcb5e9bbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,8 +140,9 @@ set(SOUND_INPUT_INCLUDES "") set(SOUND_INPUT_LIBRARY "") set(SOUND_DEFINE "") if (USE_FFMPEG) - find_package(FFMPEG REQUIRED) - set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIR}) + set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) + find_package(FFmpeg REQUIRED) + set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS}) set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES}) set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG) endif (USE_FFMPEG) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 7b028e1d0..a6e80fc9b 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -10,8 +10,8 @@ #include extern "C" { -#include -#include +#include +#include } #include "sound_decoder.hpp" diff --git a/cmake/FindFFMPEG.cmake b/cmake/FindFFMPEG.cmake deleted file mode 100644 index 2e755d047..000000000 --- a/cmake/FindFFMPEG.cmake +++ /dev/null @@ -1,105 +0,0 @@ -# Find the FFmpeg library -# -# Sets -# FFMPEG_FOUND. If false, don't try to use ffmpeg -# FFMPEG_INCLUDE_DIR -# FFMPEG_LIBRARIES -# -# Modified by Nicolay Korslund for OpenMW - -SET( FFMPEG_FOUND "NO" ) - -FIND_PATH( FFMPEG_general_INCLUDE_DIR libavcodec/avcodec.h libavformat/avformat.h - HINTS - PATHS - /usr/include - /usr/local/include - /usr/include/ffmpeg - /usr/local/include/ffmpeg - /usr/include/ffmpeg/libavcodec - /usr/local/include/ffmpeg/libavcodec - /usr/include/libavcodec - /usr/local/include/libavcodec - ) - -FIND_PATH( FFMPEG_avcodec_INCLUDE_DIR avcodec.h - HINTS - PATHS - ${FFMPEG_general_INCLUDE_DIR}/libavcodec - /usr/include - /usr/local/include - /usr/include/ffmpeg - /usr/local/include/ffmpeg - /usr/include/ffmpeg/libavcodec - /usr/local/include/ffmpeg/libavcodec - /usr/include/libavcodec - /usr/local/include/libavcodec -) - -FIND_PATH( FFMPEG_avformat_INCLUDE_DIR avformat.h - HINTS - PATHS - ${FFMPEG_general_INCLUDE_DIR}/libavformat - /usr/include - /usr/local/include - /usr/include/ffmpeg - /usr/local/include/ffmpeg - /usr/include/ffmpeg/libavformat - /usr/local/include/ffmpeg/libavformat - /usr/include/libavformat - /usr/local/include/libavformat -) - -set(FFMPEG_INCLUDE_DIR ${FFMPEG_general_INCLUDE_DIR} ${FFMPEG_avcodec_INCLUDE_DIR} ${FFMPEG_avformat_INCLUDE_DIR}) - -IF( FFMPEG_INCLUDE_DIR ) - -FIND_PROGRAM( FFMPEG_CONFIG ffmpeg-config - /usr/bin - /usr/local/bin - ${HOME}/bin -) - -IF( FFMPEG_CONFIG ) - EXEC_PROGRAM( ${FFMPEG_CONFIG} ARGS "--libs avformat" OUTPUT_VARIABLE FFMPEG_LIBS ) - SET( FFMPEG_FOUND "YES" ) - SET( FFMPEG_LIBRARIES "${FFMPEG_LIBS}" ) - -ELSE( FFMPEG_CONFIG ) - - FIND_LIBRARY( FFMPEG_avcodec_LIBRARY avcodec - /usr/lib - /usr/local/lib - /usr/lib64 - /usr/local/lib64 - ) - - FIND_LIBRARY( FFMPEG_avformat_LIBRARY avformat - /usr/lib - /usr/local/lib - /usr/lib64 - /usr/local/lib64 - ) - - FIND_LIBRARY( FFMPEG_avutil_LIBRARY avutil - /usr/lib - /usr/local/lib - /usr/lib64 - /usr/local/lib64 - ) - - IF( FFMPEG_avcodec_LIBRARY ) - IF( FFMPEG_avformat_LIBRARY ) - - SET( FFMPEG_FOUND "YES" ) - SET( FFMPEG_LIBRARIES ${FFMPEG_avformat_LIBRARY} ${FFMPEG_avcodec_LIBRARY} ) - IF( FFMPEG_avutil_LIBRARY ) - SET( FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${FFMPEG_avutil_LIBRARY} ) - ENDIF( FFMPEG_avutil_LIBRARY ) - - ENDIF( FFMPEG_avformat_LIBRARY ) - ENDIF( FFMPEG_avcodec_LIBRARY ) - -ENDIF( FFMPEG_CONFIG ) - -ENDIF( FFMPEG_INCLUDE_DIR ) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake new file mode 100644 index 000000000..526be5f1b --- /dev/null +++ b/cmake/FindFFmpeg.cmake @@ -0,0 +1,148 @@ +# vim: ts=2 sw=2 +# - Try to find the required ffmpeg components(default: AVFORMAT, AVUTIL, AVCODEC) +# +# Once done this will define +# FFMPEG_FOUND - System has the all required components. +# FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers. +# FFMPEG_LIBRARIES - Link these to use the required ffmpeg components. +# FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components. +# +# For each of the components it will additionaly set. +# - AVCODEC +# - AVDEVICE +# - AVFORMAT +# - AVUTIL +# - POSTPROCESS +# - SWSCALE +# the following variables will be defined +# _FOUND - System has +# _INCLUDE_DIRS - Include directory necessary for using the headers +# _LIBRARIES - Link these to use +# _DEFINITIONS - Compiler switches required for using +# _VERSION - The components version +# +# Copyright (c) 2006, Matthias Kretz, +# Copyright (c) 2008, Alexander Neundorf, +# Copyright (c) 2011, Michael Jansen, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +include(FindPackageHandleStandardArgs) + +# The default components were taken from a survey over other FindFFMPEG.cmake files +if (NOT FFmpeg_FIND_COMPONENTS) + set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL) +endif () + +# +### Macro: set_component_found +# +# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present. +# +macro(set_component_found _component ) + if (${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS) + # message(STATUS " - ${_component} found.") + set(${_component}_FOUND TRUE) + else () + # message(STATUS " - ${_component} not found.") + endif () +endmacro() + +# +### Macro: find_component +# +# Checks for the given component by invoking pkgconfig and then looking up the libraries and +# include directories. +# +macro(find_component _component _pkgconfig _library _header) + + if (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(PC_${_component} ${_pkgconfig}) + endif () + endif (NOT WIN32) + + find_path(${_component}_INCLUDE_DIRS ${_header} + HINTS + ${PC_LIB${_component}_INCLUDEDIR} + ${PC_LIB${_component}_INCLUDE_DIRS} + PATH_SUFFIXES + ffmpeg + ) + + find_library(${_component}_LIBRARIES NAMES ${_library} + HINTS + ${PC_LIB${_component}_LIBDIR} + ${PC_LIB${_component}_LIBRARY_DIRS} + ) + + set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.") + set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.") + + set_component_found(${_component}) + + mark_as_advanced( + ${_component}_INCLUDE_DIRS + ${_component}_LIBRARIES + ${_component}_DEFINITIONS + ${_component}_VERSION) + +endmacro() + + +# Check for cached results. If there are skip the costly part. +if (NOT FFMPEG_LIBRARIES) + + # Check for all possible component. + find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) + find_component(AVFORMAT libavformat avformat libavformat/avformat.h) + find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h) + find_component(AVUTIL libavutil avutil libavutil/avutil.h) + find_component(SWSCALE libswscale swscale libswscale/swscale.h) + find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h) + + # Check if the required components were found and add their stuff to the FFMPEG_* vars. + foreach (_component ${FFmpeg_FIND_COMPONENTS}) + if (${_component}_FOUND) + # message(STATUS "Required component ${_component} present.") + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARIES}) + set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS}) + list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS}) + else () + # message(STATUS "Required component ${_component} missing.") + endif () + endforeach () + + # Build the include path with duplicates removed. + if (FFMPEG_INCLUDE_DIRS) + list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS) + endif () + + # cache the vars. + set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE) + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE) + set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE) + + mark_as_advanced(FFMPEG_INCLUDE_DIRS + FFMPEG_LIBRARIES + FFMPEG_DEFINITIONS) + +endif () + +# Now set the noncached _FOUND vars for the components. +foreach (_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWSCALE) + set_component_found(${_component}) +endforeach () + +# Compile the list of required vars +set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS) +foreach (_component ${FFmpeg_FIND_COMPONENTS}) + list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS) +endforeach () + +# Give a nice error message if some of the required vars are missing. +find_package_handle_standard_args(FFmpeg DEFAULT_MSG ${_FFmpeg_REQUIRED_VARS}) From db29e411c4a28805611ce7d90e0ee8294af09cb8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 3 Dec 2012 13:56:02 +0100 Subject: [PATCH 039/916] added merge functions; temporarily merge on document creation --- apps/opencs/editor.cpp | 2 ++ apps/opencs/model/world/columns.hpp | 3 +++ apps/opencs/model/world/data.cpp | 5 ++++ apps/opencs/model/world/data.hpp | 3 +++ apps/opencs/model/world/idcollection.hpp | 30 ++++++++++++++++++++++++ apps/opencs/model/world/record.hpp | 30 ++++++++++++++++++++++-- 6 files changed, 71 insertions(+), 2 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 6977a22f0..1632ed220 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -35,6 +35,8 @@ void CS::Editor::createDocument() document->getData().getGlobals().add (record); } + document->getData().merge(); /// \todo remove once proper ESX loading is implemented + mViewManager.addView (document); } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index e81780cee..483ce929d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -51,6 +51,9 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { + if (record.mState==Record::State_Erased) + return static_cast (Record::State_Deleted); + return static_cast (record.mState); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c0df54c10..f350299ec 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -46,4 +46,9 @@ QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) throw std::logic_error ("No table model available for " + id.toString()); return iter->second; +} + +void CSMWorld::Data::merge() +{ + mGlobals.merge(); } \ No newline at end of file diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 11073c5e3..a8a21e205 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -33,6 +33,9 @@ namespace CSMWorld QAbstractTableModel *getTableModel (const UniversalId& id); ///< If no table model is available for \æ id, an exception is thrown. + + void merge(); + ///< Merge modified into base. }; } diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 41cd352ce..d9ab16747 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -58,6 +59,12 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data) = 0; virtual bool isEditable (int column) const = 0; + + virtual void merge() = 0; + ///< Merge modified into base. + + virtual void purge() = 0; + ///< Remove records that are flagged as erased. }; ///< \brief Collection of ID-based records @@ -95,6 +102,12 @@ namespace CSMWorld virtual bool isEditable (int column) const; + virtual void merge(); + ///< Merge modified into base. + + virtual void purge(); + ///< Remove records that are flagged as erased. + void addColumn (Column *column); }; @@ -181,6 +194,23 @@ namespace CSMWorld { mColumns.push_back (column); } + + template + void IdCollection::merge() + { + for (typename std::vector >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter) + iter->merge(); + + purge(); + } + + template + void IdCollection::purge() + { + mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(), + std::mem_fun_ref (&Record::isErased) // I want lambda :( + ), mRecords.end()); + } } #endif diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 950d7f176..c08d2e0d1 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -13,7 +13,8 @@ namespace CSMWorld State_BaseOnly, // defined in base only State_Modified, // exists in base, but has been modified State_ModifiedOnly, // newly created in modified - State_Deleted // exists in base, but has been deleted + State_Deleted, // exists in base, but has been deleted + State_Erased // does not exist at all (we mostly treat that the same way as deleted) }; ESXRecordT mBase; @@ -22,6 +23,8 @@ namespace CSMWorld bool isDeleted() const; + bool isErased() const; + bool isModified() const; const ESXRecordT& get() const; @@ -32,12 +35,21 @@ namespace CSMWorld void setModified (const ESXRecordT& modified); ///< Throws an exception, if the record is deleted. + + void merge(); + ///< Merge modified into base. }; template bool Record::isDeleted() const { - return mState==State_Deleted; + return mState==State_Deleted || mState==State_Erased; + } + + template + bool Record::isErased() const + { + return mState==State_Erased; } template @@ -75,6 +87,20 @@ namespace CSMWorld if (mState!=State_ModifiedOnly) mState = mBase==mModified ? State_BaseOnly : State_Modified; } + + template + void Record::merge() + { + if (isModified()) + { + mBase = mModified; + mState = State_BaseOnly; + } + else if (mState==State_Deleted) + { + mState = State_Erased; + } + } } #endif From a77d910aaf10e90dde397c92daf8bdef2e927a41 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 3 Dec 2012 16:44:41 +0100 Subject: [PATCH 040/916] audio codec is opened, some cleanup --- apps/openmw/mwrender/videoplayer.cpp | 77 +++++++++++++++++++--------- apps/openmw/mwrender/videoplayer.hpp | 12 +++-- 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 4679104d8..5e7d8eb55 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -72,6 +72,7 @@ namespace MWRender VideoPlayer::VideoPlayer(Ogre::SceneManager *sceneMgr) : mAvContext(NULL) , mVideoStreamId(-1) + , mAudioStreamId(-1) { Ogre::MaterialPtr videoMaterial = Ogre::MaterialManager::getSingleton ().create("VideoMaterial", "General"); videoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); @@ -108,6 +109,7 @@ namespace MWRender mVideoStreamId = -1; + mAudioStreamId = -1; mEOF = false; mDisplayedFrameCount = 0; @@ -150,36 +152,60 @@ namespace MWRender - // INIT VIDEO - // Find the video stream among the different streams for (unsigned int i = 0; i < mAvContext->nb_streams; i++) { if (mAvContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { mVideoStreamId = i; + mVideoStream = mAvContext->streams[i]; break; } } - if (-1 == mVideoStreamId) + if (mVideoStreamId < 0) throw std::runtime_error("No video stream found in the video"); - // Get the video codec - mVideoCodecContext = mAvContext->streams[mVideoStreamId]->codec; - if (!mVideoCodecContext) - throw std::runtime_error("Stream doesn't have a codec"); - // Get the video decoder - mVideoCodec = avcodec_find_decoder(mVideoCodecContext->codec_id); + mVideoCodec = avcodec_find_decoder(mVideoStream->codec->codec_id); if (NULL == mVideoCodec) - throw std::runtime_error("No decoder found"); + throw std::runtime_error("No video decoder found"); // Load the video codec - err = avcodec_open2(mVideoCodecContext, mVideoCodec, 0); + err = avcodec_open2(mVideoStream->codec, mVideoCodec, 0); if (err < 0) throwError (err); + + + // Find the audio stream among the different streams + for (unsigned int i = 0; i < mAvContext->nb_streams; i++) + { + if (mAvContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) + { + mAudioStreamId = i; + mAudioStream = mAvContext->streams[i]; + break; + } + } + + if (-1 == mAudioStreamId) + throw std::runtime_error("No audio stream found in the video"); + + // Get the audio decoder + mAudioCodec = avcodec_find_decoder(mAudioStream->codec->codec_id); + if (mAudioCodec == NULL) + { + throw std::runtime_error("Stream doesn't have an audio codec"); + } + + // Load the audio codec + err = avcodec_open2(mAudioStream->codec, mAudioCodec, 0); + if (err < 0) + throwError (err); + + + // Create the frame buffers mRawFrame = avcodec_alloc_frame(); mRGBAFrame = avcodec_alloc_frame(); @@ -189,23 +215,23 @@ namespace MWRender } - avpicture_alloc ((AVPicture *)mRGBAFrame, PIX_FMT_RGBA, mVideoCodecContext->width, mVideoCodecContext->height); + avpicture_alloc ((AVPicture *)mRGBAFrame, PIX_FMT_RGBA, mVideoStream->codec->width, mVideoStream->codec->height); // Setup the image scaler // All this does is convert from YUV to RGB - note it would be faster to do this in a shader, // but i'm not worried about performance just yet - mSwsContext = sws_getContext(mVideoCodecContext->width, mVideoCodecContext->height, - mVideoCodecContext->pix_fmt, - mVideoCodecContext->width, mVideoCodecContext->height, + mSwsContext = sws_getContext(mVideoStream->codec->width, mVideoStream->codec->height, + mVideoStream->codec->pix_fmt, + mVideoStream->codec->width, mVideoStream->codec->height, PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); if (!mSwsContext) throw std::runtime_error("Can't create SWS Context"); // Get the frame time we need for this video - AVRational r = mAvContext->streams[mVideoStreamId]->avg_frame_rate; - AVRational r2 = mAvContext->streams[mVideoStreamId]->r_frame_rate; + AVRational r = mVideoStream->avg_frame_rate; + AVRational r2 = mVideoStream->r_frame_rate; if ((!r.num || !r.den) && (!r2.num || !r2.den)) { @@ -230,19 +256,19 @@ namespace MWRender "VideoTexture", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, - mVideoCodecContext->width, mVideoCodecContext->height, + mVideoStream->codec->width, mVideoStream->codec->height, 0, Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); // initialize to (0, 0, 0, 1) std::vector buffer; - buffer.resize(mVideoCodecContext->width * mVideoCodecContext->height); - for (int p=0; pwidth * mVideoCodecContext->height; ++p) + buffer.resize(mVideoStream->codec->width * mVideoStream->codec->height); + for (int p=0; pcodec->width * mVideoStream->codec->height; ++p) { buffer[p] = (255 << 24); } - memcpy(mVideoTexture->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mVideoCodecContext->width*mVideoCodecContext->height*4); + memcpy(mVideoTexture->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mVideoStream->codec->width*mVideoStream->codec->height*4); mVideoTexture->getBuffer()->unlock(); mTextureUnit->setTextureName ("VideoTexture"); @@ -358,7 +384,7 @@ namespace MWRender // Get the front frame and decode it AVPacket *videoPacket = mVideoPacketQueue.front(); int res; - res = avcodec_decode_video2(mVideoCodecContext, mRawFrame, &didDecodeFrame, videoPacket); + res = avcodec_decode_video2(mVideoStream->codec, mRawFrame, &didDecodeFrame, videoPacket); if (res < 0 || !didDecodeFrame) throw std::runtime_error ("an error occured while decoding the video frame"); @@ -366,12 +392,12 @@ namespace MWRender // Convert the frame to RGB sws_scale(mSwsContext, mRawFrame->data, mRawFrame->linesize, - 0, mVideoCodecContext->height, + 0, mVideoStream->codec->height, mRGBAFrame->data, mRGBAFrame->linesize); Ogre::HardwarePixelBufferSharedPtr pixelBuffer = mVideoTexture->getBuffer(); - Ogre::PixelBox pb(mVideoCodecContext->width, mVideoCodecContext->height, 1, Ogre::PF_BYTE_RGBA, mRGBAFrame->data[0]); + Ogre::PixelBox pb(mVideoStream->codec->width, mVideoStream->codec->height, 1, Ogre::PF_BYTE_RGBA, mRGBAFrame->data[0]); pixelBuffer->blitFromMemory(pb); av_free_packet(mVideoPacketQueue.front()); @@ -397,7 +423,8 @@ namespace MWRender mVideoPacketQueue.pop(); } - avcodec_close(mVideoCodecContext); + if (mVideoStream && mVideoStream->codec != NULL) avcodec_close(mVideoStream->codec); + if (mAudioStream && mAudioStream->codec != NULL) avcodec_close(mAudioStream->codec); avpicture_free((AVPicture *)mRGBAFrame); diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 1d3010e8e..5010ac516 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -21,6 +21,7 @@ namespace Ogre struct AVFormatContext; struct AVCodecContext; struct AVCodec; +struct AVStream; struct AVFrame; struct SwsContext; struct AVPacket; @@ -56,10 +57,14 @@ namespace MWRender Ogre::Timer mTimer; - // VIDEO - AVCodecContext* mVideoCodecContext; AVCodec* mVideoCodec; - int mVideoStreamId; + AVCodec* mAudioCodec; + + AVStream* mVideoStream; + AVStream* mAudioStream; + int mVideoStreamId; ///< ID of the first video stream + int mAudioStreamId; ///< ID of the first audio stream + AVFrame* mRawFrame; AVFrame* mRGBAFrame; SwsContext* mSwsContext; @@ -67,6 +72,7 @@ namespace MWRender float mDecodingTime; std::queue mVideoPacketQueue; + int mDisplayedFrameCount; From bc90c751760dc9bdb894a8e781e3da335d2c92e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 3 Dec 2012 17:33:02 +0100 Subject: [PATCH 041/916] more clean up, video played with correct speed, videos without sound working too (mw_credits.bik) --- apps/openmw/mwrender/videoplayer.cpp | 315 +++++++++++++++++---------- apps/openmw/mwrender/videoplayer.hpp | 45 +++- 2 files changed, 228 insertions(+), 132 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 5e7d8eb55..e7f1eccde 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -19,6 +19,9 @@ extern "C" #include "../mwbase/environment.hpp" +#define MIN_QUEUED_PACKETS 30 + + namespace MWRender { @@ -69,10 +72,76 @@ namespace MWRender return stream->tell(); } + //------------------------------------------------------------------------------------------- + + AVPacketQueue::AVPacketQueue(): + mFirstPacket(NULL), mLastPacket(NULL), mNumPackets(0), mSize(0) + + { + } + + int AVPacketQueue::put(AVPacket* pkt) + { + if(av_dup_packet(pkt) < 0) + { + return -1; + } + + AVPacketList* pkt1; + pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); + if (pkt1 == NULL) return -1; + pkt1->pkt = *pkt; + pkt1->next = NULL; + + if (mLastPacket == NULL) mFirstPacket = pkt1; + else mLastPacket->next = pkt1; + + mLastPacket = pkt1; + mNumPackets++; + mSize += pkt1->pkt.size; + + return 0; + } + + int AVPacketQueue::get(AVPacket* pkt, int block) + { + AVPacketList* pkt1; + + while (true) + { + pkt1 = mFirstPacket; + if (pkt1 != NULL) + { + mFirstPacket = pkt1->next; + + if (mFirstPacket == NULL) mLastPacket = NULL; + + mNumPackets--; + mSize -= pkt1->pkt.size; + *pkt = pkt1->pkt; + av_free(pkt1); + return 1; + } + else if (block == 0) + { + return 0; + } + else + { + return -1; + } + } + } + + //------------------------------------------------------------------------------------------- + VideoPlayer::VideoPlayer(Ogre::SceneManager *sceneMgr) : mAvContext(NULL) , mVideoStreamId(-1) , mAudioStreamId(-1) + , mVideoClock(0) + , mAudioClock(0) + , mClock(0) { Ogre::MaterialPtr videoMaterial = Ogre::MaterialManager::getSingleton ().create("VideoMaterial", "General"); videoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); @@ -110,8 +179,11 @@ namespace MWRender mVideoStreamId = -1; mAudioStreamId = -1; - mEOF = false; - mDisplayedFrameCount = 0; + mAudioStream = NULL; + mVideoStream = NULL; + mVideoClock = 0; + mAudioClock = 0; + mClock = 0; // if something is already playing, close it if (mAvContext) @@ -189,20 +261,20 @@ namespace MWRender } } - if (-1 == mAudioStreamId) - throw std::runtime_error("No audio stream found in the video"); - - // Get the audio decoder - mAudioCodec = avcodec_find_decoder(mAudioStream->codec->codec_id); - if (mAudioCodec == NULL) + if (mAudioStreamId >= 0) { - throw std::runtime_error("Stream doesn't have an audio codec"); - } + // Get the audio decoder + mAudioCodec = avcodec_find_decoder(mAudioStream->codec->codec_id); + if (mAudioCodec == NULL) + { + throw std::runtime_error("Stream doesn't have an audio codec"); + } - // Load the audio codec - err = avcodec_open2(mAudioStream->codec, mAudioCodec, 0); - if (err < 0) - throwError (err); + // Load the audio codec + err = avcodec_open2(mAudioStream->codec, mAudioCodec, 0); + if (err < 0) + throwError (err); + } @@ -229,24 +301,6 @@ namespace MWRender if (!mSwsContext) throw std::runtime_error("Can't create SWS Context"); - // Get the frame time we need for this video - AVRational r = mVideoStream->avg_frame_rate; - AVRational r2 = mVideoStream->r_frame_rate; - if ((!r.num || !r.den) && - (!r2.num || !r2.den)) - { - std::cerr << "Warning - unable to get the video frame rate. Using standard NTSC frame rate : 29.97 fps." << std::endl; - mWantedFrameTime = 1.f / 29.97f; - } - else - { - if (r.num && r.den) - mWantedFrameTime = 1.f/((float)r.num / r.den); - else - mWantedFrameTime = 1.f/((float)r2.num / r2.den); - } - - mTextureUnit->setTextureName (""); if (!Ogre::TextureManager::getSingleton ().getByName("VideoTexture").isNull()) @@ -273,8 +327,23 @@ namespace MWRender mTextureUnit->setTextureName ("VideoTexture"); - mTimer.reset(); + // Queue up some packets + while( + mVideoPacketQueue.getNumPackets()stream_index == mVideoStreamId) - { - // If it was a video frame... - mVideoPacketQueue.push(frame); - saved = true; - } - - return saved; - - } - void VideoPlayer::update() { if (!mAvContext) return; - // Time elapsed since the video started - float realTime = mTimer.getMilliseconds ()/1000.f; + double dt = mTimer.getMilliseconds () / 1000.f; + mTimer.reset (); - // Here is the time we're at in the video - float movieTime = mDisplayedFrameCount * mWantedFrameTime; - - if (movieTime >= realTime) - return; - - if (!mVideoPacketQueue.size() && mEOF) - close(); - - Ogre::Timer timer; - - if (!mVideoPacketQueue.size()) + //UpdateAudio(fTime); + std::cout << "num packets: " << mVideoPacketQueue.getNumPackets() << " clocks: " << mVideoClock << " , " << mClock << std::endl; + while (!mVideoPacketQueue.isEmpty() && mVideoClock < mClock) { - if (readFrameAndQueue()) - decodeFrontFrame(); - } - else - decodeFrontFrame(); + while( + mVideoPacketQueue.getNumPackets()codec, mRawFrame, &didDecodeFrame, videoPacket); + int didDecodeFrame = 0; + res = avcodec_decode_video2(mVideoStream->codec, mRawFrame, &didDecodeFrame, &packet); if (res < 0 || !didDecodeFrame) throw std::runtime_error ("an error occured while decoding the video frame"); + // Set video clock to the PTS of this packet (presentation timestamp) + double pts = 0; + if (packet.pts != -1.0) pts = packet.pts; + pts *= av_q2d(mVideoStream->time_base); + mVideoClock = pts; + // Convert the frame to RGB sws_scale(mSwsContext, mRawFrame->data, mRawFrame->linesize, @@ -400,11 +433,7 @@ namespace MWRender Ogre::PixelBox pb(mVideoStream->codec->width, mVideoStream->codec->height, 1, Ogre::PF_BYTE_RGBA, mRGBAFrame->data[0]); pixelBuffer->blitFromMemory(pb); - av_free_packet(mVideoPacketQueue.front()); - av_free(mVideoPacketQueue.front()); - mVideoPacketQueue.pop(); - - ++mDisplayedFrameCount; + if (packet.data != NULL) av_free_packet(&packet); } void VideoPlayer::close () @@ -416,11 +445,17 @@ namespace MWRender void VideoPlayer::deleteContext() { - while (mVideoPacketQueue.size()) + while (mVideoPacketQueue.getNumPackets ()) { - av_free_packet(mVideoPacketQueue.front()); - av_free(mVideoPacketQueue.front()); - mVideoPacketQueue.pop(); + AVPacket packet; + mVideoPacketQueue.get(&packet, 1); + if (packet.data != NULL) av_free_packet(&packet); + } + while (mAudioPacketQueue.getNumPackets ()) + { + AVPacket packet; + mAudioPacketQueue.get(&packet, 1); + if (packet.data != NULL) av_free_packet(&packet); } if (mVideoStream && mVideoStream->codec != NULL) avcodec_close(mVideoStream->codec); @@ -439,6 +474,46 @@ namespace MWRender mAvContext = NULL; } + + + + bool VideoPlayer::addToBuffer() + { + if(mAvContext) + { + AVPacket packet; + if (av_read_frame(mAvContext, &packet) >= 0) + { + if (packet.stream_index == mVideoStreamId) + { + /* + if(curTime==0) + { + curTime = packet.dts; + curTime *= av_q2d(m_pVideoSt->time_base); + std::cout << "Initializing curtime to: " << curTime << std::endl; + } + */ + + mVideoPacketQueue.put(&packet); + + return true; + } + else if (packet.stream_index == mAudioStreamId && mAudioStream) + { + mAudioPacketQueue.put(&packet); + return true; + } + else + { + av_free_packet(&packet); + return false; + } + } + } + + return false; + } } //#endif diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 5010ac516..466bb7902 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -25,10 +25,31 @@ struct AVStream; struct AVFrame; struct SwsContext; struct AVPacket; +struct AVPacketList; namespace MWRender { + /// A simple queue used to queue raw audio and video data. + class AVPacketQueue + { + public: + AVPacketQueue(); + int put(AVPacket* pkt); + int get(AVPacket* pkt, int block); + + bool isEmpty() const { return mNumPackets == 0; } + int getNumPackets() const { return mNumPackets; } + int getSize() const { return mSize; } + + private: + AVPacketList* mFirstPacket; + AVPacketList* mLastPacket; + int mNumPackets; + int mSize; + }; + + class VideoPlayer { public: @@ -52,9 +73,6 @@ namespace MWRender AVFormatContext* mAvContext; - - bool mEOF; - Ogre::Timer mTimer; AVCodec* mVideoCodec; @@ -68,24 +86,27 @@ namespace MWRender AVFrame* mRawFrame; AVFrame* mRGBAFrame; SwsContext* mSwsContext; - float mWantedFrameTime; - float mDecodingTime; - std::queue mVideoPacketQueue; + double mClock; + double mVideoClock; + double mAudioClock; - int mDisplayedFrameCount; + AVPacketQueue mVideoPacketQueue; + AVPacketQueue mAudioPacketQueue; - bool readFrameAndQueue(); - bool saveFrame(AVPacket* frame); - - void decodeFrontFrame(); - void close(); void deleteContext(); void throwError(int error); + + + + + bool addToBuffer(); ///< try to add the next audio or video packet into the queue. + + void decodeNextVideoFrame(); ///< decode the next video frame in the queue and display it. }; } From 3106db0379fabb77b8c17b601c39274360bf4d47 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 3 Dec 2012 17:41:38 +0100 Subject: [PATCH 042/916] commented out debug output --- apps/openmw/mwrender/videoplayer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index e7f1eccde..b1fee213f 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -370,7 +370,7 @@ namespace MWRender mTimer.reset (); //UpdateAudio(fTime); - std::cout << "num packets: " << mVideoPacketQueue.getNumPackets() << " clocks: " << mVideoClock << " , " << mClock << std::endl; + //std::cout << "num packets: " << mVideoPacketQueue.getNumPackets() << " clocks: " << mVideoClock << " , " << mClock << std::endl; while (!mVideoPacketQueue.isEmpty() && mVideoClock < mClock) { while( @@ -486,12 +486,13 @@ namespace MWRender { if (packet.stream_index == mVideoStreamId) { + // I don't believe this is necessary. /* - if(curTime==0) + if(mClock==0) { - curTime = packet.dts; - curTime *= av_q2d(m_pVideoSt->time_base); - std::cout << "Initializing curtime to: " << curTime << std::endl; + mClock = packet.dts; + mClock *= av_q2d(mVideoStream->time_base); + std::cout << "Initializing clock to: " << mClock << std::endl; } */ From 49d62390045bfc3794f98da72fee9ce0351415fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 3 Dec 2012 21:44:16 +0100 Subject: [PATCH 043/916] added pop-up menu with create record action --- apps/opencs/CMakeLists.txt | 6 +- apps/opencs/model/world/commands.cpp | 18 ++++++ apps/opencs/model/world/commands.hpp | 18 ++++++ apps/opencs/model/world/idcollection.hpp | 56 +++++++++++++++++++ apps/opencs/model/world/idtable.cpp | 30 ++++++++++ apps/opencs/model/world/idtable.hpp | 18 ++++-- apps/opencs/model/world/idtableproxymodel.cpp | 18 ++++++ apps/opencs/model/world/idtableproxymodel.hpp | 24 ++++++++ apps/opencs/model/world/record.hpp | 17 +++--- apps/opencs/view/world/globals.cpp | 2 +- apps/opencs/view/world/table.cpp | 45 +++++++++++++-- apps/opencs/view/world/table.hpp | 18 +++++- 12 files changed, 246 insertions(+), 24 deletions(-) create mode 100644 apps/opencs/model/world/idtableproxymodel.cpp create mode 100644 apps/opencs/model/world/idtableproxymodel.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index dfd987345..6d18a1811 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -5,7 +5,7 @@ set (OPENCS_SRC model/doc/documentmanager.cpp model/doc/document.cpp model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp - model/world/commands.cpp + model/world/commands.cpp model/world/idtableproxymodel.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp @@ -18,10 +18,10 @@ set (OPENCS_HDR model/doc/documentmanager.hpp model/doc/document.hpp model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp - model/world/idtable.hpp model/world/columns.hpp + model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp + model/world/commands.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp - model/world/commands.hpp view/world/subview.hpp view/world/table.hpp view/world/globals.hpp ) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index a15d00619..7bb76acd0 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -3,6 +3,8 @@ #include +#include "idtableproxymodel.hpp" + CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand *parent) : QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) @@ -20,4 +22,20 @@ void CSMWorld::ModifyCommand::redo() void CSMWorld::ModifyCommand::undo() { mModel.setData (mIndex, mOld); +} + +CSMWorld::CreateCommand::CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mId (id) +{ + setText (("Create record " + id).c_str()); +} + +void CSMWorld::CreateCommand::redo() +{ + mModel.addRecord (mId); +} + +void CSMWorld::CreateCommand::undo() +{ + mModel.removeRow (mModel.getModelIndex (mId, 0).row()); } \ No newline at end of file diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index ffaee59ef..50b9045c6 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -3,6 +3,8 @@ #include "record.hpp" +#include + #include #include #include @@ -12,6 +14,8 @@ class QAbstractItemModel; namespace CSMWorld { + class IdTableProxyModel; + class ModifyCommand : public QUndoCommand { QAbstractItemModel& mModel; @@ -28,6 +32,20 @@ namespace CSMWorld virtual void undo(); }; + + class CreateCommand : public QUndoCommand + { + IdTableProxyModel& mModel; + std::string mId; + + public: + + CreateCommand (IdTableProxyModel& model, const std::string& id, QUndoCommand *parent = 0); + + virtual void redo(); + + virtual void undo(); + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index d9ab16747..be7891bd2 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -50,6 +50,8 @@ namespace CSMWorld virtual std::string getId (int index) const = 0; + virtual int getIndex (const std::string& id) const = 0; + virtual int getColumns() const = 0; virtual std::string getTitle (int column) const = 0; @@ -65,6 +67,10 @@ namespace CSMWorld virtual void purge() = 0; ///< Remove records that are flagged as erased. + + virtual void removeRows (int index, int count) = 0; + + virtual void appendBlankRecord (const std::string& id) = 0; }; ///< \brief Collection of ID-based records @@ -92,6 +98,8 @@ namespace CSMWorld virtual std::string getId (int index) const; + virtual int getIndex (const std::string& id) const; + virtual int getColumns() const; virtual QVariant getData (int index, int column) const; @@ -108,6 +116,10 @@ namespace CSMWorld virtual void purge(); ///< Remove records that are flagged as erased. + virtual void removeRows (int index, int count) ; + + virtual void appendBlankRecord (const std::string& id); + void addColumn (Column *column); }; @@ -159,6 +171,17 @@ namespace CSMWorld return mRecords.at (index).get().mId; } + template + int IdCollection::getIndex (const std::string& id) const + { + std::map::const_iterator iter = mIndex.find (id); + + if (iter==mIndex.end()) + throw std::runtime_error ("invalid ID: " + id); + + return iter->second; + } + template int IdCollection::getColumns() const { @@ -211,6 +234,39 @@ namespace CSMWorld std::mem_fun_ref (&Record::isErased) // I want lambda :( ), mRecords.end()); } + + template + void IdCollection::removeRows (int index, int count) + { + mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count); + + typename std::map::iterator iter = mIndex.begin(); + + while (iter!=mIndex.end()) + { + if (iter->second>=index) + { + if (iter->second>=index+count) + { + iter->second -= count; + } + else + { + mIndex.erase (iter++); + } + } + + ++iter; + } + } + + template + void IdCollection::appendBlankRecord (const std::string& id) + { + ESXRecordT record; + record.mId = id; + add (record); + } } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 1fc2bfedb..50a6953d6 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -71,4 +71,34 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const flags |= Qt::ItemIsEditable; return flags; +} + +bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent) +{ + if (parent.isValid()) + return false; + + beginRemoveRows (parent, row, row+count-1); + + mIdCollection->removeRows (row, count); + + endRemoveRows(); + + return true; +} + +void CSMWorld::IdTable::addRecord (const std::string& id) +{ + int index = mIdCollection->getSize(); + + beginInsertRows (QModelIndex(), index, index); + + mIdCollection->appendBlankRecord (id); + + endInsertRows(); +} + +QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const +{ + return index (mIdCollection->getIndex (id), column); } \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 30af3aaf7..f95873c7a 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -24,17 +24,23 @@ namespace CSMWorld virtual ~IdTable(); - int rowCount (const QModelIndex & parent = QModelIndex()) const; + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; - int columnCount (const QModelIndex & parent = QModelIndex()) const; + virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; - QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - Qt::ItemFlags flags (const QModelIndex & index) const; + virtual Qt::ItemFlags flags (const QModelIndex & index) const; + + virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + + void addRecord (const std::string& id); + + QModelIndex getModelIndex (const std::string& id, int column) const; }; } diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp new file mode 100644 index 000000000..78995f60b --- /dev/null +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -0,0 +1,18 @@ + +#include "idtableproxymodel.hpp" + +#include "idtable.hpp" + +CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) +: QSortFilterProxyModel (parent) +{} + +void CSMWorld::IdTableProxyModel::addRecord (const std::string& id) +{ + dynamic_cast (*sourceModel()).addRecord (id); +} + +QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const +{ + return mapFromSource (dynamic_cast (*sourceModel()).getModelIndex (id, column)); +} \ No newline at end of file diff --git a/apps/opencs/model/world/idtableproxymodel.hpp b/apps/opencs/model/world/idtableproxymodel.hpp new file mode 100644 index 000000000..3f1537cce --- /dev/null +++ b/apps/opencs/model/world/idtableproxymodel.hpp @@ -0,0 +1,24 @@ +#ifndef CSM_WOLRD_IDTABLEPROXYMODEL_H +#define CSM_WOLRD_IDTABLEPROXYMODEL_H + +#include + +#include + +namespace CSMWorld +{ + class IdTableProxyModel : public QSortFilterProxyModel + { + Q_OBJECT + + public: + + IdTableProxyModel (QObject *parent = 0); + + virtual void addRecord (const std::string& id); + + virtual QModelIndex getModelIndex (const std::string& id, int column) const; + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index c08d2e0d1..df93501f3 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -5,18 +5,21 @@ namespace CSMWorld { - template - struct Record + struct RecordBase { enum State { - State_BaseOnly, // defined in base only - State_Modified, // exists in base, but has been modified - State_ModifiedOnly, // newly created in modified - State_Deleted, // exists in base, but has been deleted - State_Erased // does not exist at all (we mostly treat that the same way as deleted) + State_BaseOnly = 0, // defined in base only + State_Modified = 1, // exists in base, but has been modified + State_ModifiedOnly = 2, // newly created in modified + State_Deleted = 3, // exists in base, but has been deleted + State_Erased = 4 // does not exist at all (we mostly treat that the same way as deleted) }; + }; + template + struct Record : public RecordBase + { ESXRecordT mBase; ESXRecordT mModified; State mState; diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp index 68c9012aa..20cdb80f4 100644 --- a/apps/opencs/view/world/globals.cpp +++ b/apps/opencs/view/world/globals.cpp @@ -6,7 +6,7 @@ CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) : SubView (id) { - setWidget (mTable = new Table (id, data, undoStack)); + setWidget (mTable = new Table (id, data, undoStack, true)); } void CSVWorld::Globals::setEditLock (bool locked) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 590f7ea98..862ebdc79 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -3,12 +3,14 @@ #include #include -#include #include +#include +#include +#include #include "../../model/world/data.hpp" - #include "../../model/world/commands.hpp" +#include "../../model/world/idtableproxymodel.hpp" namespace CSVWorld { @@ -104,7 +106,19 @@ void CSVWorld::CommandDelegate::setEditLock (bool locked) } -CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) + void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) +{ + QMenu menu (this); + + if (mCreateAction) + menu.addAction (mCreateAction); + + menu.exec (event->globalPos()); +} + +CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, + bool createAndDelete) +: mUndoStack (undoStack), mCreateAction (0) { QAbstractTableModel *model = data.getTableModel (id); @@ -117,10 +131,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q setItemDelegateForColumn (i, delegate); } - QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel (this); - proxyModel->setSourceModel (model); + mModel = new CSMWorld::IdTableProxyModel (this); + mModel->setSourceModel (model); - setModel (proxyModel); + setModel (mModel); horizontalHeader()->setResizeMode (QHeaderView::Interactive); verticalHeader()->hide(); setSortingEnabled (true); @@ -128,10 +142,29 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q setSelectionMode (QAbstractItemView::ExtendedSelection); /// \todo make initial layout fill the whole width of the table + + if (createAndDelete) + { + mCreateAction = new QAction (tr ("CreateRecord"), this); + connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord())); + addAction (mCreateAction); + } } void CSVWorld::Table::setEditLock (bool locked) { for (std::vector::iterator iter (mDelegates.begin()); iter!=mDelegates.end(); ++iter) (*iter)->setEditLock (locked); +} + +#include /// \todo remove +void CSVWorld::Table::createRecord() +{ + /// \todo ask the user for an ID instead. + static int index = 0; + + std::ostringstream stream; + stream << "id" << index++; + + mUndoStack.push (new CSMWorld::CreateCommand (*mModel, stream.str())); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index ae203f516..f07f3ff24 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -6,11 +6,13 @@ #include class QUndoStack; +class QAction; namespace CSMWorld { class Data; class UniversalId; + class IdTableProxyModel; } namespace CSVWorld @@ -20,13 +22,27 @@ namespace CSVWorld ///< Table widget class Table : public QTableView { + Q_OBJECT + std::vector mDelegates; + QUndoStack& mUndoStack; + QAction *mCreateAction; + CSMWorld::IdTableProxyModel *mModel; + + private: + + void contextMenuEvent (QContextMenuEvent *event); public: - Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); + Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete); + ///< \param createAndDelete Allow creation and deletion of records. void setEditLock (bool locked); + + private slots: + + void createRecord(); }; } From 0a8b7602d316c63d2909270be035d2137a6551a3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 3 Dec 2012 21:51:42 +0100 Subject: [PATCH 044/916] fixed edit lock --- apps/opencs/view/doc/view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3d5ebc84b..1a8d56878 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -169,7 +169,7 @@ void CSVDoc::View::updateDocumentState() QList subViews = findChildren(); for (QList::iterator iter (subViews.begin()); iter!=subViews.end(); ++iter) - (*iter)->setEditLock (state && CSMDoc::Document::State_Locked); + (*iter)->setEditLock (state & CSMDoc::Document::State_Locked); } void CSVDoc::View::updateProgress (int current, int max, int type, int threads) From 8e93bfa607ba7e38a507e7ffe346df0f5c9ecaec Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 3 Dec 2012 22:03:02 +0100 Subject: [PATCH 045/916] turned the global class into a general purpose table subview class --- apps/opencs/CMakeLists.txt | 4 ++-- apps/opencs/view/doc/view.cpp | 5 ++--- apps/opencs/view/world/globals.cpp | 15 --------------- apps/opencs/view/world/globals.hpp | 24 ------------------------ apps/opencs/view/world/subview.hpp | 23 +++++++++++++++++++++++ apps/opencs/view/world/table.cpp | 2 +- apps/opencs/view/world/tablesubview.cpp | 16 ++++++++++++++++ apps/opencs/view/world/tablesubview.hpp | 25 +++++++++++++++++++++++++ 8 files changed, 69 insertions(+), 45 deletions(-) delete mode 100644 apps/opencs/view/world/globals.cpp delete mode 100644 apps/opencs/view/world/globals.hpp create mode 100644 apps/opencs/view/world/tablesubview.cpp create mode 100644 apps/opencs/view/world/tablesubview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6d18a1811..4ef4f93c7 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -9,7 +9,7 @@ set (OPENCS_SRC view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp - view/world/subview.cpp view/world/table.cpp view/world/globals.cpp + view/world/subview.cpp view/world/table.cpp view/world/tablesubview.cpp ) set (OPENCS_HDR @@ -23,7 +23,7 @@ set (OPENCS_HDR view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp - view/world/subview.hpp view/world/table.hpp view/world/globals.hpp + view/world/subview.hpp view/world/table.hpp view/world/tablesubview.hpp ) set (OPENCS_US diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 1a8d56878..65ec103a2 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -10,8 +10,7 @@ #include "../../model/doc/document.hpp" -#include "../world/subview.hpp" -#include "../world/globals.hpp" +#include "../world/tablesubview.hpp" #include "viewmanager.hpp" #include "operations.hpp" @@ -122,7 +121,7 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to setupUi(); mSubViewFactories.insert (std::make_pair (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), - new CSVWorld::SubViewFactory())); + new CSVWorld::SubViewFactoryWithCreateFlag (true))); } CSVDoc::View::~View() diff --git a/apps/opencs/view/world/globals.cpp b/apps/opencs/view/world/globals.cpp deleted file mode 100644 index 20cdb80f4..000000000 --- a/apps/opencs/view/world/globals.cpp +++ /dev/null @@ -1,15 +0,0 @@ - -#include "globals.hpp" - -#include "table.hpp" - -CSVWorld::Globals::Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) -: SubView (id) -{ - setWidget (mTable = new Table (id, data, undoStack, true)); -} - -void CSVWorld::Globals::setEditLock (bool locked) -{ - mTable->setEditLock (locked); -} \ No newline at end of file diff --git a/apps/opencs/view/world/globals.hpp b/apps/opencs/view/world/globals.hpp deleted file mode 100644 index 33cbce47f..000000000 --- a/apps/opencs/view/world/globals.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef CSV_WORLD_GLOBALS_H -#define CSV_WORLD_GLOBALS_H - -#include "subview.hpp" - -class QUndoStack; - -namespace CSVWorld -{ - class Table; - - class Globals : public SubView - { - Table *mTable; - - public: - - Globals (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); - - virtual void setEditLock (bool locked); - }; -} - -#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subview.hpp b/apps/opencs/view/world/subview.hpp index 543a9b2a1..95448cb47 100644 --- a/apps/opencs/view/world/subview.hpp +++ b/apps/opencs/view/world/subview.hpp @@ -51,6 +51,29 @@ namespace CSVWorld { return new SubViewT (id, data, undoStack); } + + template + struct SubViewFactoryWithCreateFlag : public SubViewFactoryBase + { + bool mCreateAndDelete; + + SubViewFactoryWithCreateFlag (bool createAndDelete); + + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); + }; + + template + SubViewFactoryWithCreateFlag::SubViewFactoryWithCreateFlag (bool createAndDelete) + : mCreateAndDelete (createAndDelete) + {} + + template + SubView *SubViewFactoryWithCreateFlag::makeSubView (const CSMWorld::UniversalId& id, + CSMWorld::Data& data, + QUndoStack& undoStack) + { + return new SubViewT (id, data, undoStack, mCreateAndDelete); + } } #endif \ No newline at end of file diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 862ebdc79..4f20d9fd2 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -145,7 +145,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q if (createAndDelete) { - mCreateAction = new QAction (tr ("CreateRecord"), this); + mCreateAction = new QAction (tr ("Add Record"), this); connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord())); addAction (mCreateAction); } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp new file mode 100644 index 000000000..3bc555a2d --- /dev/null +++ b/apps/opencs/view/world/tablesubview.cpp @@ -0,0 +1,16 @@ + +#include "tablesubview.hpp" + +#include "table.hpp" + +CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, + bool createAndDelete) +: SubView (id) +{ + setWidget (mTable = new Table (id, data, undoStack, createAndDelete)); +} + +void CSVWorld::TableSubView::setEditLock (bool locked) +{ + mTable->setEditLock (locked); +} \ No newline at end of file diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp new file mode 100644 index 000000000..b45b3c279 --- /dev/null +++ b/apps/opencs/view/world/tablesubview.hpp @@ -0,0 +1,25 @@ +#ifndef CSV_WORLD_TABLESUBVIEW_H +#define CSV_WORLD_TABLESUBVIEW_H + +#include "subview.hpp" + +class QUndoStack; + +namespace CSVWorld +{ + class Table; + + class TableSubView : public SubView + { + Table *mTable; + + public: + + TableSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, + bool createAndDelete); + + virtual void setEditLock (bool locked); + }; +} + +#endif \ No newline at end of file From 5cd2fe00ab41eaef4618e017061fd86630987338 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 3 Dec 2012 22:16:02 +0100 Subject: [PATCH 046/916] initialise blank global records --- apps/opencs/model/world/idcollection.hpp | 1 + components/esm/loadglob.cpp | 6 ++++++ components/esm/loadglob.hpp | 3 +++ 3 files changed, 10 insertions(+) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index be7891bd2..e4bb31dbe 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -265,6 +265,7 @@ namespace CSMWorld { ESXRecordT record; record.mId = id; + record.blank(); add (record); } } diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 0335da0df..ceaa86948 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -44,6 +44,12 @@ void Global::save(ESMWriter &esm) esm.writeHNT("FLTV", mValue); } + void Global::blank() + { + mValue = 0; + mType = VT_Float; + } + bool operator== (const Global& left, const Global& right) { return left.mId==right.mId && left.mValue==right.mValue && left.mType==right.mType; diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 5c5dafaec..6111648a6 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -23,6 +23,9 @@ struct Global void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID). }; bool operator== (const Global& left, const Global& right); From f07b7d17cdb1e07d907fe1518bd7249b695e64f3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 4 Dec 2012 20:43:47 +0100 Subject: [PATCH 047/916] improved exception handling --- apps/opencs/main.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 15772eba0..4b1a688c2 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -1,11 +1,37 @@ #include "editor.hpp" +#include +#include + #include +class Application : public QApplication +{ + private: + + bool notify (QObject *receiver, QEvent *event) + { + try + { + return QApplication::notify (receiver, event); + } + catch (const std::exception& exception) + { + std::cerr << "An exception has been caught: " << exception.what() << std::endl; + } + + return false; + } + + public: + + Application (int& argc, char *argv[]) : QApplication (argc, argv) {} +}; + int main(int argc, char *argv[]) { - QApplication mApplication (argc, argv); + Application mApplication (argc, argv); CS::Editor editor; From b41cc5e9e943580281b7be67262de633c41f8404 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Dec 2012 14:56:04 +0100 Subject: [PATCH 048/916] added revert command --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columns.hpp | 7 +- apps/opencs/model/world/commands.cpp | 34 +++++++++ apps/opencs/model/world/commands.hpp | 23 +++++++ apps/opencs/model/world/idcollection.hpp | 87 +++++++++++++++++++++++- apps/opencs/model/world/idtable.cpp | 32 ++++++++- apps/opencs/model/world/idtable.hpp | 6 ++ apps/opencs/model/world/record.cpp | 21 ++++++ apps/opencs/model/world/record.hpp | 35 ++++------ apps/opencs/view/world/table.cpp | 55 +++++++++++++-- apps/opencs/view/world/table.hpp | 7 +- 11 files changed, 275 insertions(+), 34 deletions(-) create mode 100644 apps/opencs/model/world/record.cpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4ef4f93c7..5a9e1e99c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -5,7 +5,7 @@ set (OPENCS_SRC model/doc/documentmanager.cpp model/doc/document.cpp model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp - model/world/commands.cpp model/world/idtableproxymodel.cpp + model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 483ce929d..188d3a2ac 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -57,9 +57,14 @@ namespace CSMWorld return static_cast (record.mState); } + virtual void set (Record& record, const QVariant& data) + { + record.mState = static_cast (data.toInt()); + } + virtual bool isEditable() const { - return false; + return true; } }; } diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 7bb76acd0..96a1b639c 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -4,6 +4,7 @@ #include #include "idtableproxymodel.hpp" +#include "idtable.hpp" CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand *parent) @@ -38,4 +39,37 @@ void CSMWorld::CreateCommand::redo() void CSMWorld::CreateCommand::undo() { mModel.removeRow (mModel.getModelIndex (mId, 0).row()); +} + +CSMWorld::RevertCommand::RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mId (id), mOld (0) +{ + setText (("Revert record " + id).c_str()); + + mOld = model.getRecord (id).clone(); +} + +CSMWorld::RevertCommand::~RevertCommand() +{ + delete mOld; +} + +void CSMWorld::RevertCommand::redo() +{ + QModelIndex index = mModel.getModelIndex (mId, 1); + RecordBase::State state = static_cast (mModel.data (index).toInt()); + + if (state==RecordBase::State_ModifiedOnly) + { + mModel.removeRows (index.row(), 1); + } + else + { + mModel.setData (index, static_cast (RecordBase::State_BaseOnly)); + } +} + +void CSMWorld::RevertCommand::undo() +{ + mModel.setRecord (*mOld); } \ No newline at end of file diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 50b9045c6..e916d05c9 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -15,6 +15,8 @@ class QAbstractItemModel; namespace CSMWorld { class IdTableProxyModel; + class IdTable; + class RecordBase; class ModifyCommand : public QUndoCommand { @@ -46,6 +48,27 @@ namespace CSMWorld virtual void undo(); }; + + class RevertCommand : public QUndoCommand + { + IdTable& mModel; + std::string mId; + RecordBase *mOld; + + // not implemented + RevertCommand (const RevertCommand&); + RevertCommand& operator= (const RevertCommand&); + + public: + + RevertCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0); + + virtual ~RevertCommand(); + + virtual void redo(); + + virtual void undo(); + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index e4bb31dbe..50afa715e 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -71,6 +71,25 @@ namespace CSMWorld virtual void removeRows (int index, int count) = 0; virtual void appendBlankRecord (const std::string& id) = 0; + + virtual int searchId (const std::string& id) const = 0; + ////< Search record with \a id. + /// \return index of record (if found) or -1 (not found) + + virtual void replace (int index, const RecordBase& record) = 0; + ///< If the record type does not match, an exception is thrown. + /// + /// \attention \a record must not change the ID. + + virtual void appendRecord (const RecordBase& record) = 0; + ///< If the record type does not match, an exception is thrown. + + virtual std::string getId (const RecordBase& record) const = 0; + ///< Return ID for \a record. + /// + /// \attention Throw san exception, if the type of \a record does not match. + + virtual const RecordBase& getRecord (const std::string& id) const = 0; }; ///< \brief Collection of ID-based records @@ -120,6 +139,25 @@ namespace CSMWorld virtual void appendBlankRecord (const std::string& id); + virtual int searchId (const std::string& id) const; + ////< Search record with \a id. + /// \return index of record (if found) or -1 (not found) + + virtual void replace (int index, const RecordBase& record); + ///< If the record type does not match, an exception is thrown. + /// + /// \attention \a record must not change the ID. + + virtual void appendRecord (const RecordBase& record); + ///< If the record type does not match, an exception is thrown. + + virtual std::string getId (const RecordBase& record) const; + ///< Return ID for \a record. + /// + /// \attention Throw san exception, if the type of \a record does not match. + + virtual const RecordBase& getRecord (const std::string& id) const; + void addColumn (Column *column); }; @@ -174,12 +212,12 @@ namespace CSMWorld template int IdCollection::getIndex (const std::string& id) const { - std::map::const_iterator iter = mIndex.find (id); + int index = searchId (id); - if (iter==mIndex.end()) + if (index==-1) throw std::runtime_error ("invalid ID: " + id); - return iter->second; + return index; } template @@ -268,6 +306,49 @@ namespace CSMWorld record.blank(); add (record); } + + template + int IdCollection::searchId (const std::string& id) const + { + std::string id2; + + std::transform (id.begin(), id.end(), std::back_inserter (id2), + (int(*)(int)) std::tolower); + + std::map::const_iterator iter = mIndex.find (id2); + + if (iter==mIndex.end()) + return -1; + + return iter->second; + } + + template + void IdCollection::replace (int index, const RecordBase& record) + { + mRecords.at (index) = dynamic_cast&> (record); + } + + template + void IdCollection::appendRecord (const RecordBase& record) + { + mRecords.push_back (dynamic_cast&> (record)); + mIndex.insert (std::make_pair (getId (record), mRecords.size()-1)); + } + + template + std::string IdCollection::getId (const RecordBase& record) const + { + const Record& record2 = dynamic_cast&> (record); + return (record2.isModified() ? record2.mModified : record2.mBase).mId; + } + + template + const RecordBase& IdCollection::getRecord (const std::string& id) const + { + int index = getIndex (id); + return mRecords.at (index); + } } #endif diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 50a6953d6..a2b0a3c1f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -56,7 +56,10 @@ bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &valu if (mIdCollection->isEditable (index.column()) && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); - emit dataChanged (index, index); + + emit dataChanged (CSMWorld::IdTable::index (index.row(), 0), + CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1)); + return true; } @@ -101,4 +104,31 @@ void CSMWorld::IdTable::addRecord (const std::string& id) QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const { return index (mIdCollection->getIndex (id), column); +} + +void CSMWorld::IdTable::setRecord (const RecordBase& record) +{ + int index = mIdCollection->searchId (mIdCollection->getId (record)); + + if (index==-1) + { + int index = mIdCollection->getSize(); + + beginInsertRows (QModelIndex(), index, index); + + mIdCollection->appendRecord (record); + + endInsertRows(); + } + else + { + mIdCollection->replace (index, record); + emit dataChanged (CSMWorld::IdTable::index (index, 0), + CSMWorld::IdTable::index (index, mIdCollection->getColumns()-1)); + } +} + +const CSMWorld::RecordBase& CSMWorld::IdTable::getRecord (const std::string& id) const +{ + return mIdCollection->getRecord (id); } \ No newline at end of file diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index f95873c7a..deaebaa38 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -6,6 +6,7 @@ namespace CSMWorld { class IdCollectionBase; + class RecordBase; class IdTable : public QAbstractTableModel { @@ -41,6 +42,11 @@ namespace CSMWorld void addRecord (const std::string& id); QModelIndex getModelIndex (const std::string& id, int column) const; + + void setRecord (const RecordBase& record); + ///< Add record or overwrite existing recrod. + + const RecordBase& getRecord (const std::string& id) const; }; } diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp new file mode 100644 index 000000000..229985a8a --- /dev/null +++ b/apps/opencs/model/world/record.cpp @@ -0,0 +1,21 @@ + +#include "record.hpp" + +CSMWorld::RecordBase::~RecordBase() {} + +bool CSMWorld::RecordBase::RecordBase::isDeleted() const +{ + return mState==State_Deleted || mState==State_Erased; +} + + +bool CSMWorld::RecordBase::RecordBase::isErased() const +{ + return mState==State_Erased; +} + + +bool CSMWorld::RecordBase::RecordBase::isModified() const +{ + return mState==State_Modified || mState==State_ModifiedOnly; +} \ No newline at end of file diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index df93501f3..3b83836ab 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -15,6 +15,18 @@ namespace CSMWorld State_Deleted = 3, // exists in base, but has been deleted State_Erased = 4 // does not exist at all (we mostly treat that the same way as deleted) }; + + State mState; + + virtual ~RecordBase(); + + virtual RecordBase *clone() const = 0; + + bool isDeleted() const; + + bool isErased() const; + + bool isModified() const; }; template @@ -22,13 +34,8 @@ namespace CSMWorld { ESXRecordT mBase; ESXRecordT mModified; - State mState; - bool isDeleted() const; - - bool isErased() const; - - bool isModified() const; + virtual RecordBase *clone() const; const ESXRecordT& get() const; ///< Throws an exception, if the record is deleted. @@ -44,21 +51,9 @@ namespace CSMWorld }; template - bool Record::isDeleted() const + RecordBase *Record::clone() const { - return mState==State_Deleted || mState==State_Erased; - } - - template - bool Record::isErased() const - { - return mState==State_Erased; - } - - template - bool Record::isModified() const - { - return mState==State_Modified || mState==State_ModifiedOnly; + return new Record (*this); } template diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 4f20d9fd2..dafcb95c0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -11,6 +11,8 @@ #include "../../model/world/data.hpp" #include "../../model/world/commands.hpp" #include "../../model/world/idtableproxymodel.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/record.hpp" namespace CSVWorld { @@ -108,11 +110,16 @@ void CSVWorld::CommandDelegate::setEditLock (bool locked) void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { - QMenu menu (this); + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + QMenu menu (this); if (mCreateAction) menu.addAction (mCreateAction); + if (selectedRows.size()>0) + menu.addAction (mRevertAction); + menu.exec (event->globalPos()); } @@ -120,9 +127,9 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q bool createAndDelete) : mUndoStack (undoStack), mCreateAction (0) { - QAbstractTableModel *model = data.getTableModel (id); + mModel = &dynamic_cast (*data.getTableModel (id)); - int columns = model->columnCount(); + int columns = mModel->columnCount(); for (int i=0; isetSourceModel (model); + mProxyModel = new CSMWorld::IdTableProxyModel (this); + mProxyModel->setSourceModel (mModel); - setModel (mModel); + setModel (mProxyModel); horizontalHeader()->setResizeMode (QHeaderView::Interactive); verticalHeader()->hide(); setSortingEnabled (true); @@ -149,6 +156,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q connect (mCreateAction, SIGNAL (triggered()), this, SLOT (createRecord())); addAction (mCreateAction); } + + mRevertAction = new QAction (tr ("Revert Record"), this); + connect (mRevertAction, SIGNAL (triggered()), this, SLOT (revertRecord())); + addAction (mRevertAction); } void CSVWorld::Table::setEditLock (bool locked) @@ -166,5 +177,35 @@ void CSVWorld::Table::createRecord() std::ostringstream stream; stream << "id" << index++; - mUndoStack.push (new CSMWorld::CreateCommand (*mModel, stream.str())); + mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str())); +} + +void CSVWorld::Table::revertRecord() +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + std::vector revertableIds; + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) + { + std::string id = mProxyModel->data (*iter).toString().toStdString(); + + CSMWorld::RecordBase::State state = + static_cast (mModel->data (mModel->getModelIndex (id, 1)).toInt()); + + if (state!=CSMWorld::RecordBase::State_BaseOnly) + revertableIds.push_back (id); + } + + if (revertableIds.size()>0) + { + if (revertableIds.size()>1) + mUndoStack.beginMacro (tr ("Revert multiple records")); + + for (std::vector::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter) + mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter)); + + if (revertableIds.size()>1) + mUndoStack.endMacro(); + } } \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index f07f3ff24..022d4f12a 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -13,6 +13,7 @@ namespace CSMWorld class Data; class UniversalId; class IdTableProxyModel; + class IdTable; } namespace CSVWorld @@ -27,7 +28,9 @@ namespace CSVWorld std::vector mDelegates; QUndoStack& mUndoStack; QAction *mCreateAction; - CSMWorld::IdTableProxyModel *mModel; + QAction *mRevertAction; + CSMWorld::IdTableProxyModel *mProxyModel; + CSMWorld::IdTable *mModel; private: @@ -43,6 +46,8 @@ namespace CSVWorld private slots: void createRecord(); + + void revertRecord(); }; } From c12ee129f7019f5664f3a25b28e8f8961b5121bb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Dec 2012 15:18:41 +0100 Subject: [PATCH 049/916] added delete command --- apps/opencs/model/world/commands.cpp | 33 +++++++++++++++++++++++++ apps/opencs/model/world/commands.hpp | 21 ++++++++++++++++ apps/opencs/model/world/record.hpp | 6 ++--- apps/opencs/view/world/table.cpp | 37 ++++++++++++++++++++++++++++ apps/opencs/view/world/table.hpp | 3 +++ 5 files changed, 97 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 96a1b639c..e22ecf992 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -70,6 +70,39 @@ void CSMWorld::RevertCommand::redo() } void CSMWorld::RevertCommand::undo() +{ + mModel.setRecord (*mOld); +} + +CSMWorld::DeleteCommand::DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent) +: QUndoCommand (parent), mModel (model), mId (id), mOld (0) +{ + setText (("Delete record " + id).c_str()); + + mOld = model.getRecord (id).clone(); +} + +CSMWorld::DeleteCommand::~DeleteCommand() +{ + delete mOld; +} + +void CSMWorld::DeleteCommand::redo() +{ + QModelIndex index = mModel.getModelIndex (mId, 1); + RecordBase::State state = static_cast (mModel.data (index).toInt()); + + if (state==RecordBase::State_ModifiedOnly) + { + mModel.removeRows (index.row(), 1); + } + else + { + mModel.setData (index, static_cast (RecordBase::State_Deleted)); + } +} + +void CSMWorld::DeleteCommand::undo() { mModel.setRecord (*mOld); } \ No newline at end of file diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index e916d05c9..af419215d 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -69,6 +69,27 @@ namespace CSMWorld virtual void undo(); }; + + class DeleteCommand : public QUndoCommand + { + IdTable& mModel; + std::string mId; + RecordBase *mOld; + + // not implemented + DeleteCommand (const DeleteCommand&); + DeleteCommand& operator= (const DeleteCommand&); + + public: + + DeleteCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0); + + virtual ~DeleteCommand(); + + virtual void redo(); + + virtual void undo(); + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 3b83836ab..53bb7ea2c 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -59,7 +59,7 @@ namespace CSMWorld template const ESXRecordT& Record::get() const { - if (isDeleted()) + if (mState==State_Erased) throw std::logic_error ("attempt to access a deleted record"); return mState==State_BaseOnly ? mBase : mModified; @@ -68,7 +68,7 @@ namespace CSMWorld template const ESXRecordT& Record::getBase() const { - if (isDeleted()) + if (mState==State_Erased) throw std::logic_error ("attempt to access a deleted record"); return mState==State_ModifiedOnly ? mModified : mBase; @@ -77,7 +77,7 @@ namespace CSMWorld template void Record::setModified (const ESXRecordT& modified) { - if (isDeleted()) + if (mState==State_Erased) throw std::logic_error ("attempt to modify a deleted record"); mModified = modified; diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index dafcb95c0..1595b6926 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -120,6 +120,9 @@ void CSVWorld::CommandDelegate::setEditLock (bool locked) if (selectedRows.size()>0) menu.addAction (mRevertAction); + if (selectedRows.size()>0) + menu.addAction (mDeleteAction); + menu.exec (event->globalPos()); } @@ -160,6 +163,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q mRevertAction = new QAction (tr ("Revert Record"), this); connect (mRevertAction, SIGNAL (triggered()), this, SLOT (revertRecord())); addAction (mRevertAction); + + mDeleteAction = new QAction (tr ("Delete Record"), this); + connect (mDeleteAction, SIGNAL (triggered()), this, SLOT (deleteRecord())); + addAction (mDeleteAction); } void CSVWorld::Table::setEditLock (bool locked) @@ -205,6 +212,36 @@ void CSVWorld::Table::revertRecord() for (std::vector::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter) mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter)); + if (revertableIds.size()>1) + mUndoStack.endMacro(); + } +} + +void CSVWorld::Table::deleteRecord() +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + std::vector revertableIds; + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) + { + std::string id = mProxyModel->data (*iter).toString().toStdString(); + + CSMWorld::RecordBase::State state = + static_cast (mModel->data (mModel->getModelIndex (id, 1)).toInt()); + + if (state!=CSMWorld::RecordBase::State_Deleted) + revertableIds.push_back (id); + } + + if (revertableIds.size()>0) + { + if (revertableIds.size()>1) + mUndoStack.beginMacro (tr ("Delete multiple records")); + + for (std::vector::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter) + mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter)); + if (revertableIds.size()>1) mUndoStack.endMacro(); } diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 022d4f12a..555dc8e1f 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -29,6 +29,7 @@ namespace CSVWorld QUndoStack& mUndoStack; QAction *mCreateAction; QAction *mRevertAction; + QAction *mDeleteAction; CSMWorld::IdTableProxyModel *mProxyModel; CSMWorld::IdTable *mModel; @@ -48,6 +49,8 @@ namespace CSVWorld void createRecord(); void revertRecord(); + + void deleteRecord(); }; } From 2b53cf6547f9611be8e4c6508865437a331f373c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Dec 2012 15:25:31 +0100 Subject: [PATCH 050/916] do not list actions in the pop up menu that do not apply to any of the selected records --- apps/opencs/view/world/table.cpp | 85 ++++++++++++++++++-------------- apps/opencs/view/world/table.hpp | 5 ++ 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 1595b6926..31f7d22ed 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -107,8 +107,7 @@ void CSVWorld::CommandDelegate::setEditLock (bool locked) mEditLock = locked; } - - void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) +void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { QModelIndexList selectedRows = selectionModel()->selectedRows(); @@ -117,15 +116,55 @@ void CSVWorld::CommandDelegate::setEditLock (bool locked) if (mCreateAction) menu.addAction (mCreateAction); - if (selectedRows.size()>0) + if (listRevertableSelectedIds().size()>0) menu.addAction (mRevertAction); - if (selectedRows.size()>0) + if (listDeletableSelectedIds().size()>0) menu.addAction (mDeleteAction); menu.exec (event->globalPos()); } +std::vector CSVWorld::Table::listRevertableSelectedIds() const +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + std::vector revertableIds; + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) + { + std::string id = mProxyModel->data (*iter).toString().toStdString(); + + CSMWorld::RecordBase::State state = + static_cast (mModel->data (mModel->getModelIndex (id, 1)).toInt()); + + if (state!=CSMWorld::RecordBase::State_BaseOnly) + revertableIds.push_back (id); + } + + return revertableIds; +} + +std::vector CSVWorld::Table::listDeletableSelectedIds() const +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + std::vector deletableIds; + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) + { + std::string id = mProxyModel->data (*iter).toString().toStdString(); + + CSMWorld::RecordBase::State state = + static_cast (mModel->data (mModel->getModelIndex (id, 1)).toInt()); + + if (state!=CSMWorld::RecordBase::State_Deleted) + deletableIds.push_back (id); + } + + return deletableIds; +} + CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete) : mUndoStack (undoStack), mCreateAction (0) @@ -189,20 +228,7 @@ void CSVWorld::Table::createRecord() void CSVWorld::Table::revertRecord() { - QModelIndexList selectedRows = selectionModel()->selectedRows(); - - std::vector revertableIds; - - for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) - { - std::string id = mProxyModel->data (*iter).toString().toStdString(); - - CSMWorld::RecordBase::State state = - static_cast (mModel->data (mModel->getModelIndex (id, 1)).toInt()); - - if (state!=CSMWorld::RecordBase::State_BaseOnly) - revertableIds.push_back (id); - } + std::vector revertableIds = listRevertableSelectedIds(); if (revertableIds.size()>0) { @@ -219,30 +245,17 @@ void CSVWorld::Table::revertRecord() void CSVWorld::Table::deleteRecord() { - QModelIndexList selectedRows = selectionModel()->selectedRows(); + std::vector deletableIds = listDeletableSelectedIds(); - std::vector revertableIds; - - for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) + if (deletableIds.size()>0) { - std::string id = mProxyModel->data (*iter).toString().toStdString(); - - CSMWorld::RecordBase::State state = - static_cast (mModel->data (mModel->getModelIndex (id, 1)).toInt()); - - if (state!=CSMWorld::RecordBase::State_Deleted) - revertableIds.push_back (id); - } - - if (revertableIds.size()>0) - { - if (revertableIds.size()>1) + if (deletableIds.size()>1) mUndoStack.beginMacro (tr ("Delete multiple records")); - for (std::vector::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter) + for (std::vector::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter) mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter)); - if (revertableIds.size()>1) + if (deletableIds.size()>1) mUndoStack.endMacro(); } } \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 555dc8e1f..264d2bc5c 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -2,6 +2,7 @@ #define CSV_WORLD_TABLE_H #include +#include #include @@ -37,6 +38,10 @@ namespace CSVWorld void contextMenuEvent (QContextMenuEvent *event); + std::vector listRevertableSelectedIds() const; + + std::vector listDeletableSelectedIds() const; + public: Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete); From fdc7e93835defe57d5fca0e47515ec3aba01fda6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Dec 2012 11:59:13 +0100 Subject: [PATCH 051/916] preliminary multi-threaded verify implementation (does not actually perfom any document verification yet) --- apps/opencs/CMakeLists.txt | 4 +++ apps/opencs/model/doc/document.cpp | 42 ++++++++++++------------- apps/opencs/model/doc/document.hpp | 11 +++++-- apps/opencs/model/tools/tools.cpp | 46 ++++++++++++++++++++++++++++ apps/opencs/model/tools/tools.hpp | 45 +++++++++++++++++++++++++++ apps/opencs/model/tools/verifier.cpp | 33 ++++++++++++++++++++ apps/opencs/model/tools/verifier.hpp | 33 ++++++++++++++++++++ 7 files changed, 189 insertions(+), 25 deletions(-) create mode 100644 apps/opencs/model/tools/tools.cpp create mode 100644 apps/opencs/model/tools/tools.hpp create mode 100644 apps/opencs/model/tools/verifier.cpp create mode 100644 apps/opencs/model/tools/verifier.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5a9e1e99c..ca235042a 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -7,6 +7,8 @@ set (OPENCS_SRC model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp + model/tools/tools.cpp model/tools/verifier.cpp + view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/world/subview.cpp view/world/table.cpp view/world/tablesubview.cpp @@ -21,6 +23,8 @@ set (OPENCS_HDR model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp model/world/commands.hpp + model/tools/tools.hpp model/tools/verifier.hpp + view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/world/subview.hpp view/world/table.hpp view/world/tablesubview.hpp diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e8091b3e0..f85fde038 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -7,13 +7,16 @@ CSMDoc::Document::Document (const std::string& name) connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); + connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); + connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int))); + // dummy implementation -> remove when proper save is implemented. mSaveCount = 0; connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); // dummy implementation -> remove when proper verify is implemented. mVerifyCount = 0; - connect (&mVerifyTimer, SIGNAL(timeout()), this, SLOT (verifying())); + } QUndoStack& CSMDoc::Document::getUndoStack() @@ -53,23 +56,19 @@ void CSMDoc::Document::save() void CSMDoc::Document::verify() { mVerifyCount = 1; - mVerifyTimer.start (500); emit stateChanged (getState(), this); - emit progress (1, 20, State_Verifying, 1, this); + mTools.runVerifier(); } void CSMDoc::Document::abortOperation (int type) { + mTools.abortOperation (type); + if (type==State_Saving) { mSaveTimer.stop(); emit stateChanged (getState(), this); } - else if (type==State_Verifying) - { - mVerifyTimer.stop(); - emit stateChanged (getState(), this); - } } void CSMDoc::Document::modificationStateChanged (bool clean) @@ -77,6 +76,14 @@ void CSMDoc::Document::modificationStateChanged (bool clean) emit stateChanged (getState(), this); } +void CSMDoc::Document::operationDone (int type) +{ + if (type==State_Verifying) + mVerifyCount = 0; + + emit stateChanged (getState(), this); +} + void CSMDoc::Document::saving() { ++mSaveCount; @@ -92,20 +99,6 @@ void CSMDoc::Document::saving() } } -void CSMDoc::Document::verifying() -{ - ++mVerifyCount; - - emit progress (mVerifyCount, 20, State_Verifying, 1, this); - - if (mVerifyCount>19) - { - mVerifyCount = 0; - mVerifyTimer.stop(); - emit stateChanged (getState(), this); - } -} - const CSMWorld::Data& CSMDoc::Document::getData() const { return mData; @@ -114,4 +107,9 @@ const CSMWorld::Data& CSMDoc::Document::getData() const CSMWorld::Data& CSMDoc::Document::getData() { return mData; +} + +void CSMDoc::Document::progress (int current, int max, int type) +{ + emit progress (current, max, type, 1, this); } \ No newline at end of file diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index b414bf04d..3fe20bc80 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -9,6 +9,8 @@ #include "../world/data.hpp" +#include "../tools/tools.hpp" + namespace CSMDoc { class Document : public QObject @@ -32,12 +34,12 @@ namespace CSMDoc std::string mName; ///< \todo replace name with ESX list QUndoStack mUndoStack; CSMWorld::Data mData; + CSMTools::Tools mTools; int mSaveCount; ///< dummy implementation -> remove when proper save is implemented. QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented. int mVerifyCount; ///< dummy implementation -> remove when proper verify is implemented. - QTimer mVerifyTimer; ///< dummy implementation -> remove when proper verify is implemented. // not implemented Document (const Document&); @@ -75,11 +77,14 @@ namespace CSMDoc void modificationStateChanged (bool clean); + void operationDone (int type); + void saving(); ///< dummy implementation -> remove when proper save is implemented. - void verifying(); - ///< dummy implementation -> remove when proper verify is implemented. + public slots: + + void progress (int current, int max, int type); }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp new file mode 100644 index 000000000..941a22cff --- /dev/null +++ b/apps/opencs/model/tools/tools.cpp @@ -0,0 +1,46 @@ + +#include "tools.hpp" + +#include + +#include "verifier.hpp" + +#include "../doc/document.hpp" + +CSMTools::Verifier *CSMTools::Tools::getVerifier() +{ + if (!mVerifier) + { + mVerifier = new Verifier; + + connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (mVerifier, SIGNAL (finished()), this, SLOT (verifierDone())); + } + + return mVerifier; +} + +CSMTools::Tools::Tools() : mVerifier (0) +{ + +} + +CSMTools::Tools::~Tools() +{ + delete mVerifier; +} + +void CSMTools::Tools::runVerifier() +{ + getVerifier()->start(); +} + +void CSMTools::Tools::abortOperation (int type) +{ + +} + +void CSMTools::Tools::verifierDone() +{ + emit done (CSMDoc::Document::State_Verifying); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp new file mode 100644 index 000000000..65b1d1684 --- /dev/null +++ b/apps/opencs/model/tools/tools.hpp @@ -0,0 +1,45 @@ +#ifndef CSM_TOOLS_TOOLS_H +#define CSM_TOOLS_TOOLS_H + +#include + +namespace CSMTools +{ + class Verifier; + + class Tools : public QObject + { + Q_OBJECT + + Verifier *mVerifier; + + // not implemented + Tools (const Tools&); + Tools& operator= (const Tools&); + + Verifier *getVerifier(); + + public: + + Tools(); + + virtual ~Tools(); + + void runVerifier(); + + void abortOperation (int type); + ///< \attention The operation is not aborted immediately. + + private slots: + + void verifierDone(); + + signals: + + void progress (int current, int max, int type); + + void done (int type); + }; +} + +#endif diff --git a/apps/opencs/model/tools/verifier.cpp b/apps/opencs/model/tools/verifier.cpp new file mode 100644 index 000000000..43a864289 --- /dev/null +++ b/apps/opencs/model/tools/verifier.cpp @@ -0,0 +1,33 @@ + +#include "verifier.hpp" + +#include + +#include "../doc/document.hpp" + +void CSMTools::Verifier::run() +{ + mStep = 0; + + QTimer timer; + + timer.connect (&timer, SIGNAL (timeout()), this, SLOT (verify())); + + timer.start (0); + + exec(); +} + +void CSMTools::Verifier::abort() +{ + exit(); +} + +void CSMTools::Verifier::verify() +{ + ++mStep; + emit progress (mStep, 1000, CSMDoc::Document::State_Verifying); + + if (mStep>=1000) + exit(); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/verifier.hpp b/apps/opencs/model/tools/verifier.hpp new file mode 100644 index 000000000..0e7fae19c --- /dev/null +++ b/apps/opencs/model/tools/verifier.hpp @@ -0,0 +1,33 @@ +#ifndef CSM_TOOLS_VERIFIER_H +#define CSM_TOOLS_VERIFIER_H + +#include + +namespace CSMTools +{ + class Verifier : public QThread + { + Q_OBJECT + + int mStep; + + public: + + virtual void run(); + + signals: + + void progress (int current, int max, int type); + + public slots: + + void abort(); + + private slots: + + void verify(); + }; + +} + +#endif From a2b4f431760d0fcae95c1774ae7f6913acb1b0af Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Dec 2012 14:44:03 +0100 Subject: [PATCH 052/916] moved document state enum to a separate file --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/document.cpp | 5 ++--- apps/opencs/model/doc/document.hpp | 14 ++------------ apps/opencs/model/doc/state.hpp | 19 +++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 4 ++-- apps/opencs/model/tools/verifier.cpp | 4 ++-- apps/opencs/view/doc/operation.cpp | 4 ++-- apps/opencs/view/doc/view.cpp | 12 ++++++------ 8 files changed, 36 insertions(+), 28 deletions(-) create mode 100644 apps/opencs/model/doc/state.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ca235042a..ce83e4ea6 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -17,7 +17,7 @@ set (OPENCS_SRC set (OPENCS_HDR editor.hpp - model/doc/documentmanager.hpp model/doc/document.hpp + model/doc/documentmanager.hpp model/doc/document.hpp model/doc/state.hpp model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index f85fde038..2bd0f2e3e 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -16,7 +16,6 @@ CSMDoc::Document::Document (const std::string& name) // dummy implementation -> remove when proper verify is implemented. mVerifyCount = 0; - } QUndoStack& CSMDoc::Document::getUndoStack() @@ -32,10 +31,10 @@ int CSMDoc::Document::getState() const state |= State_Modified; if (mSaveCount) - state |= State_Locked | State_Saving; + state |= State_Locked | State_Saving | State_Operation; if (mVerifyCount) - state |= State_Locked | State_Verifying; + state |= State_Locked | State_Verifying | State_Operation; return state; } diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 3fe20bc80..6226e3165 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -11,24 +11,14 @@ #include "../tools/tools.hpp" +#include "state.hpp" + namespace CSMDoc { class Document : public QObject { Q_OBJECT - public: - - enum State - { - State_Modified = 1, - State_Locked = 2, - State_Saving = 4, - State_Verifying = 8, - State_Compiling = 16, // not implemented yet - State_Searching = 32 // not implemented yet - }; - private: std::string mName; ///< \todo replace name with ESX list diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp new file mode 100644 index 000000000..04e6fae89 --- /dev/null +++ b/apps/opencs/model/doc/state.hpp @@ -0,0 +1,19 @@ +#ifndef CSM_DOC_STATE_H +#define CSM_DOC_STATE_H + +namespace CSMDoc +{ + enum State + { + State_Modified = 1, + State_Locked = 2, + State_Operation = 4, + + State_Saving = 8, + State_Verifying = 16, + State_Compiling = 32, // not implemented yet + State_Searching = 64 // not implemented yet + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 941a22cff..95375332c 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -5,7 +5,7 @@ #include "verifier.hpp" -#include "../doc/document.hpp" +#include "../doc/state.hpp" CSMTools::Verifier *CSMTools::Tools::getVerifier() { @@ -42,5 +42,5 @@ void CSMTools::Tools::abortOperation (int type) void CSMTools::Tools::verifierDone() { - emit done (CSMDoc::Document::State_Verifying); + emit done (CSMDoc::State_Verifying); } \ No newline at end of file diff --git a/apps/opencs/model/tools/verifier.cpp b/apps/opencs/model/tools/verifier.cpp index 43a864289..14cb692e9 100644 --- a/apps/opencs/model/tools/verifier.cpp +++ b/apps/opencs/model/tools/verifier.cpp @@ -3,7 +3,7 @@ #include -#include "../doc/document.hpp" +#include "../doc/state.hpp" void CSMTools::Verifier::run() { @@ -26,7 +26,7 @@ void CSMTools::Verifier::abort() void CSMTools::Verifier::verify() { ++mStep; - emit progress (mStep, 1000, CSMDoc::Document::State_Verifying); + emit progress (mStep, 1000, CSMDoc::State_Verifying); if (mStep>=1000) exit(); diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 62f006be5..3f415da03 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -13,8 +13,8 @@ void CSVDoc::Operation::updateLabel (int threads) switch (mType) { - case CSMDoc::Document::State_Saving: name = "saving"; break; - case CSMDoc::Document::State_Verifying: name = "verifying"; break; + case CSMDoc::State_Saving: name = "saving"; break; + case CSMDoc::State_Verifying: name = "verifying"; break; } std::ostringstream stream; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 65ec103a2..539b149cb 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -83,7 +83,7 @@ void CSVDoc::View::updateTitle() stream << mDocument->getName(); - if (mDocument->getState() & CSMDoc::Document::State_Modified) + if (mDocument->getState() & CSMDoc::State_Modified) stream << " *"; if (mViewTotal>1) @@ -94,7 +94,7 @@ void CSVDoc::View::updateTitle() void CSVDoc::View::updateActions() { - bool editing = !(mDocument->getState() & CSMDoc::Document::State_Locked); + bool editing = !(mDocument->getState() & CSMDoc::State_Locked); for (std::vector::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter) (*iter)->setEnabled (editing); @@ -102,8 +102,8 @@ void CSVDoc::View::updateActions() mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo()); mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo()); - mSave->setEnabled (!(mDocument->getState() & CSMDoc::Document::State_Saving)); - mVerify->setEnabled (!(mDocument->getState() & CSMDoc::Document::State_Verifying)); + mSave->setEnabled (!(mDocument->getState() & CSMDoc::State_Saving)); + mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) @@ -155,7 +155,7 @@ void CSVDoc::View::updateDocumentState() static const int operations[] = { - CSMDoc::Document::State_Saving, CSMDoc::Document::State_Verifying, + CSMDoc::State_Saving, CSMDoc::State_Verifying, -1 // end marker }; @@ -168,7 +168,7 @@ void CSVDoc::View::updateDocumentState() QList subViews = findChildren(); for (QList::iterator iter (subViews.begin()); iter!=subViews.end(); ++iter) - (*iter)->setEditLock (state & CSMDoc::Document::State_Locked); + (*iter)->setEditLock (state & CSMDoc::State_Locked); } void CSVDoc::View::updateProgress (int current, int max, int type, int threads) From af9b48f4d333839a66b96cf23e9faa62cbfaa7c8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Dec 2012 15:25:50 +0100 Subject: [PATCH 053/916] added operations base class --- apps/opencs/CMakeLists.txt | 4 +-- apps/opencs/model/tools/operation.cpp | 35 +++++++++++++++++++++++++++ apps/opencs/model/tools/operation.hpp | 35 +++++++++++++++++++++++++++ apps/opencs/model/tools/verifier.cpp | 30 ++--------------------- apps/opencs/model/tools/verifier.hpp | 22 +++-------------- 5 files changed, 77 insertions(+), 49 deletions(-) create mode 100644 apps/opencs/model/tools/operation.cpp create mode 100644 apps/opencs/model/tools/operation.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ce83e4ea6..d2b87be51 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -7,7 +7,7 @@ set (OPENCS_SRC model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp - model/tools/tools.cpp model/tools/verifier.cpp + model/tools/tools.cpp model/tools/operation.cpp model/tools/verifier.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp @@ -23,7 +23,7 @@ set (OPENCS_HDR model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp model/world/commands.hpp - model/tools/tools.hpp model/tools/verifier.hpp + model/tools/tools.hpp model/tools/operation.hpp model/tools/verifier.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp diff --git a/apps/opencs/model/tools/operation.cpp b/apps/opencs/model/tools/operation.cpp new file mode 100644 index 000000000..ba5866168 --- /dev/null +++ b/apps/opencs/model/tools/operation.cpp @@ -0,0 +1,35 @@ + +#include "operation.hpp" + +#include + +#include "../doc/state.hpp" + +CSMTools::Operation::Operation (int type) : mType (type) {} + +void CSMTools::Operation::run() +{ + mStep = 0; + + QTimer timer; + + timer.connect (&timer, SIGNAL (timeout()), this, SLOT (verify())); + + timer.start (0); + + exec(); +} + +void CSMTools::Operation::abort() +{ + exit(); +} + +void CSMTools::Operation::verify() +{ + ++mStep; + emit progress (mStep, 1000, mType); + + if (mStep>=1000) + exit(); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/operation.hpp b/apps/opencs/model/tools/operation.hpp new file mode 100644 index 000000000..b75e2898f --- /dev/null +++ b/apps/opencs/model/tools/operation.hpp @@ -0,0 +1,35 @@ +#ifndef CSM_TOOLS_OPERATION_H +#define CSM_TOOLS_OPERATION_H + +#include + +namespace CSMTools +{ + class Operation : public QThread + { + Q_OBJECT + + int mType; + int mStep; + + public: + + Operation (int type); + + virtual void run(); + + signals: + + void progress (int current, int max, int type); + + public slots: + + void abort(); + + private slots: + + void verify(); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/tools/verifier.cpp b/apps/opencs/model/tools/verifier.cpp index 14cb692e9..9c00d4ea7 100644 --- a/apps/opencs/model/tools/verifier.cpp +++ b/apps/opencs/model/tools/verifier.cpp @@ -1,33 +1,7 @@ #include "verifier.hpp" -#include - #include "../doc/state.hpp" -void CSMTools::Verifier::run() -{ - mStep = 0; - - QTimer timer; - - timer.connect (&timer, SIGNAL (timeout()), this, SLOT (verify())); - - timer.start (0); - - exec(); -} - -void CSMTools::Verifier::abort() -{ - exit(); -} - -void CSMTools::Verifier::verify() -{ - ++mStep; - emit progress (mStep, 1000, CSMDoc::State_Verifying); - - if (mStep>=1000) - exit(); -} \ No newline at end of file +CSMTools::Verifier::Verifier() : Operation (CSMDoc::State_Verifying) +{} diff --git a/apps/opencs/model/tools/verifier.hpp b/apps/opencs/model/tools/verifier.hpp index 0e7fae19c..054f87169 100644 --- a/apps/opencs/model/tools/verifier.hpp +++ b/apps/opencs/model/tools/verifier.hpp @@ -1,33 +1,17 @@ #ifndef CSM_TOOLS_VERIFIER_H #define CSM_TOOLS_VERIFIER_H -#include +#include "operation.hpp" namespace CSMTools { - class Verifier : public QThread + class Verifier : public Operation { - Q_OBJECT - - int mStep; - public: - virtual void run(); + Verifier(); - signals: - - void progress (int current, int max, int type); - - public slots: - - void abort(); - - private slots: - - void verify(); }; - } #endif From 8b7f342641b38c740cb78bc0f137b22f2f94ba6e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Dec 2012 17:00:58 +0100 Subject: [PATCH 054/916] removed last remains of old verify implementation --- apps/opencs/model/doc/document.cpp | 13 +++--------- apps/opencs/model/doc/document.hpp | 2 -- apps/opencs/model/tools/tools.cpp | 34 ++++++++++++++++++++++++++++++ apps/opencs/model/tools/tools.hpp | 9 ++++++++ 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 2bd0f2e3e..d8ad5ff01 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -13,9 +13,6 @@ CSMDoc::Document::Document (const std::string& name) // dummy implementation -> remove when proper save is implemented. mSaveCount = 0; connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); - - // dummy implementation -> remove when proper verify is implemented. - mVerifyCount = 0; } QUndoStack& CSMDoc::Document::getUndoStack() @@ -33,8 +30,8 @@ int CSMDoc::Document::getState() const if (mSaveCount) state |= State_Locked | State_Saving | State_Operation; - if (mVerifyCount) - state |= State_Locked | State_Verifying | State_Operation; + if (int operations = mTools.getRunningOperations()) + state |= State_Locked | State_Operation | operations; return state; } @@ -54,9 +51,8 @@ void CSMDoc::Document::save() void CSMDoc::Document::verify() { - mVerifyCount = 1; - emit stateChanged (getState(), this); mTools.runVerifier(); + emit stateChanged (getState(), this); } void CSMDoc::Document::abortOperation (int type) @@ -77,9 +73,6 @@ void CSMDoc::Document::modificationStateChanged (bool clean) void CSMDoc::Document::operationDone (int type) { - if (type==State_Verifying) - mVerifyCount = 0; - emit stateChanged (getState(), this); } diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 6226e3165..40f8c0ea1 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -29,8 +29,6 @@ namespace CSMDoc int mSaveCount; ///< dummy implementation -> remove when proper save is implemented. QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented. - int mVerifyCount; ///< dummy implementation -> remove when proper verify is implemented. - // not implemented Document (const Document&); Document& operator= (const Document&); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 95375332c..608244a3c 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -7,6 +7,21 @@ #include "../doc/state.hpp" +CSMTools::Operation *CSMTools::Tools::get (int type) +{ + switch (type) + { + case CSMDoc::State_Verifying: return mVerifier; + } + + return 0; +} + +const CSMTools::Operation *CSMTools::Tools::get (int type) const +{ + return const_cast (this)->get (type); +} + CSMTools::Verifier *CSMTools::Tools::getVerifier() { if (!mVerifier) @@ -37,7 +52,26 @@ void CSMTools::Tools::runVerifier() void CSMTools::Tools::abortOperation (int type) { + if (Operation *operation = get (type)) + operation->abort(); +} +int CSMTools::Tools::getRunningOperations() const +{ + static const int sOperations[] = + { + CSMDoc::State_Verifying, + -1 + }; + + int result = 0; + + for (int i=0; sOperations[i]!=-1; ++i) + if (const Operation *operation = get (sOperations[i])) + if (operation->isRunning()) + result |= sOperations[i]; + + return result; } void CSMTools::Tools::verifierDone() diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 65b1d1684..ab1863738 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -6,6 +6,7 @@ namespace CSMTools { class Verifier; + class Operation; class Tools : public QObject { @@ -19,6 +20,12 @@ namespace CSMTools Verifier *getVerifier(); + Operation *get (int type); + ///< Returns a 0-pointer, if operation hasn't been used yet. + + const Operation *get (int type) const; + ///< Returns a 0-pointer, if operation hasn't been used yet. + public: Tools(); @@ -30,6 +37,8 @@ namespace CSMTools void abortOperation (int type); ///< \attention The operation is not aborted immediately. + int getRunningOperations() const; + private slots: void verifierDone(); From 6c18be39f0e10b43163de194fe93d0714df40eef Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Dec 2012 17:53:45 +0100 Subject: [PATCH 055/916] added stage class --- apps/opencs/CMakeLists.txt | 4 +-- apps/opencs/model/tools/operation.cpp | 49 ++++++++++++++++++++++++--- apps/opencs/model/tools/operation.hpp | 19 ++++++++++- apps/opencs/model/tools/stage.cpp | 4 +++ apps/opencs/model/tools/stage.hpp | 20 +++++++++++ 5 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 apps/opencs/model/tools/stage.cpp create mode 100644 apps/opencs/model/tools/stage.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d2b87be51..381ce51cf 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -7,7 +7,7 @@ set (OPENCS_SRC model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp - model/tools/tools.cpp model/tools/operation.cpp model/tools/verifier.cpp + model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp @@ -23,7 +23,7 @@ set (OPENCS_HDR model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp model/world/commands.hpp - model/tools/tools.hpp model/tools/operation.hpp model/tools/verifier.hpp + model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp diff --git a/apps/opencs/model/tools/operation.cpp b/apps/opencs/model/tools/operation.cpp index ba5866168..12c4a8108 100644 --- a/apps/opencs/model/tools/operation.cpp +++ b/apps/opencs/model/tools/operation.cpp @@ -5,11 +5,33 @@ #include "../doc/state.hpp" +#include "stage.hpp" + +void CSMTools::Operation::prepareStages() +{ + mCurrentStage = mStages.begin(); + mCurrentStep = 0; + mCurrentStepTotal = 0; + mTotalSteps = 0; + + for (std::vector >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter) + { + iter->second = mTotalSteps; + mTotalSteps += iter->first->setup(); + } +} + CSMTools::Operation::Operation (int type) : mType (type) {} +CSMTools::Operation::~Operation() +{ + for (std::vector >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter) + delete iter->first; +} + void CSMTools::Operation::run() { - mStep = 0; + prepareStages(); QTimer timer; @@ -20,6 +42,11 @@ void CSMTools::Operation::run() exec(); } +void CSMTools::Operation::appendStage (Stage *stage) +{ + mStages.push_back (std::make_pair (stage, 0)); +} + void CSMTools::Operation::abort() { exit(); @@ -27,9 +54,23 @@ void CSMTools::Operation::abort() void CSMTools::Operation::verify() { - ++mStep; - emit progress (mStep, 1000, mType); + while (mCurrentStage!=mStages.end()) + { + if (mCurrentStep>=mCurrentStage->second) + { + mCurrentStep = 0; + ++mCurrentStage; + } + else + { + mCurrentStage->first->perform (mCurrentStep++); + ++mCurrentStepTotal; + break; + } + } - if (mStep>=1000) + emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); + + if (mCurrentStage==mStages.end()) exit(); } \ No newline at end of file diff --git a/apps/opencs/model/tools/operation.hpp b/apps/opencs/model/tools/operation.hpp index b75e2898f..72419e00a 100644 --- a/apps/opencs/model/tools/operation.hpp +++ b/apps/opencs/model/tools/operation.hpp @@ -1,23 +1,40 @@ #ifndef CSM_TOOLS_OPERATION_H #define CSM_TOOLS_OPERATION_H +#include + #include namespace CSMTools { + class Stage; + class Operation : public QThread { Q_OBJECT int mType; - int mStep; + std::vector > mStages; // stage, number of steps + std::vector >::iterator mCurrentStage; + int mCurrentStep; + int mCurrentStepTotal; + int mTotalSteps; + + void prepareStages(); public: Operation (int type); + virtual ~Operation(); + virtual void run(); + void appendStage (Stage *stage); + ///< The ownership of \a stage is transferred to *this. + /// + /// \attention Do no call this function while this Operation is running. + signals: void progress (int current, int max, int type); diff --git a/apps/opencs/model/tools/stage.cpp b/apps/opencs/model/tools/stage.cpp new file mode 100644 index 000000000..6f4567e57 --- /dev/null +++ b/apps/opencs/model/tools/stage.cpp @@ -0,0 +1,4 @@ + +#include "stage.hpp" + +CSMTools::Stage::~Stage() {} \ No newline at end of file diff --git a/apps/opencs/model/tools/stage.hpp b/apps/opencs/model/tools/stage.hpp new file mode 100644 index 000000000..912559410 --- /dev/null +++ b/apps/opencs/model/tools/stage.hpp @@ -0,0 +1,20 @@ +#ifndef CSM_TOOLS_STAGE_H +#define CSM_TOOLS_STAGE_H + +namespace CSMTools +{ + class Stage + { + public: + + virtual ~Stage(); + + virtual int setup() = 0; + ///< \return number of steps + + virtual void perform (int stage) = 0; + }; +} + +#endif + From 89b449733128f2967cecfe47c7c15d1890e023de Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Dec 2012 18:15:00 +0100 Subject: [PATCH 056/916] added missing edit locks for create/revert/delete --- apps/opencs/view/world/table.cpp | 76 +++++++++++++++++++------------- apps/opencs/view/world/table.hpp | 1 + 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 31f7d22ed..593dc8563 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -113,14 +113,19 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) QMenu menu (this); - if (mCreateAction) - menu.addAction (mCreateAction); + /// \todo add menu items for select all and clear selection - if (listRevertableSelectedIds().size()>0) - menu.addAction (mRevertAction); + if (!mEditLock) + { + if (mCreateAction) + menu.addAction (mCreateAction); - if (listDeletableSelectedIds().size()>0) - menu.addAction (mDeleteAction); + if (listRevertableSelectedIds().size()>0) + menu.addAction (mRevertAction); + + if (listDeletableSelectedIds().size()>0) + menu.addAction (mDeleteAction); + } menu.exec (event->globalPos()); } @@ -167,7 +172,7 @@ std::vector CSVWorld::Table::listDeletableSelectedIds() const CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete) -: mUndoStack (undoStack), mCreateAction (0) +: mUndoStack (undoStack), mCreateAction (0), mEditLock (false) { mModel = &dynamic_cast (*data.getTableModel (id)); @@ -212,50 +217,61 @@ void CSVWorld::Table::setEditLock (bool locked) { for (std::vector::iterator iter (mDelegates.begin()); iter!=mDelegates.end(); ++iter) (*iter)->setEditLock (locked); + + mEditLock = locked; } #include /// \todo remove void CSVWorld::Table::createRecord() { - /// \todo ask the user for an ID instead. - static int index = 0; + if (!mEditLock) + { + /// \todo ask the user for an ID instead. + static int index = 0; - std::ostringstream stream; - stream << "id" << index++; + std::ostringstream stream; + stream << "id" << index++; - mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str())); + mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str())); + } } void CSVWorld::Table::revertRecord() { - std::vector revertableIds = listRevertableSelectedIds(); - - if (revertableIds.size()>0) + if (!mEditLock) { - if (revertableIds.size()>1) - mUndoStack.beginMacro (tr ("Revert multiple records")); + std::vector revertableIds = listRevertableSelectedIds(); - for (std::vector::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter) - mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter)); + if (revertableIds.size()>0) + { + if (revertableIds.size()>1) + mUndoStack.beginMacro (tr ("Revert multiple records")); - if (revertableIds.size()>1) - mUndoStack.endMacro(); + for (std::vector::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter) + mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter)); + + if (revertableIds.size()>1) + mUndoStack.endMacro(); + } } } void CSVWorld::Table::deleteRecord() { - std::vector deletableIds = listDeletableSelectedIds(); - - if (deletableIds.size()>0) + if (!mEditLock) { - if (deletableIds.size()>1) - mUndoStack.beginMacro (tr ("Delete multiple records")); + std::vector deletableIds = listDeletableSelectedIds(); - for (std::vector::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter) - mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter)); + if (deletableIds.size()>0) + { + if (deletableIds.size()>1) + mUndoStack.beginMacro (tr ("Delete multiple records")); - if (deletableIds.size()>1) - mUndoStack.endMacro(); + for (std::vector::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter) + mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter)); + + if (deletableIds.size()>1) + mUndoStack.endMacro(); + } } } \ No newline at end of file diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 264d2bc5c..b58ba8328 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -33,6 +33,7 @@ namespace CSVWorld QAction *mDeleteAction; CSMWorld::IdTableProxyModel *mProxyModel; CSMWorld::IdTable *mModel; + bool mEditLock; private: From 72623652e46dd5ce94b4e1b4f2593cb889db23b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Dec 2012 18:38:36 +0100 Subject: [PATCH 057/916] addded messages interface for operations/stages --- apps/opencs/model/tools/operation.cpp | 10 +++++++++- apps/opencs/model/tools/operation.hpp | 2 ++ apps/opencs/model/tools/stage.hpp | 6 +++++- apps/opencs/model/tools/tools.cpp | 10 ++++++++++ apps/opencs/model/tools/tools.hpp | 2 ++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/tools/operation.cpp b/apps/opencs/model/tools/operation.cpp index 12c4a8108..b68f79ca4 100644 --- a/apps/opencs/model/tools/operation.cpp +++ b/apps/opencs/model/tools/operation.cpp @@ -1,6 +1,9 @@ #include "operation.hpp" +#include +#include + #include #include "../doc/state.hpp" @@ -54,6 +57,8 @@ void CSMTools::Operation::abort() void CSMTools::Operation::verify() { + std::vector messages; + while (mCurrentStage!=mStages.end()) { if (mCurrentStep>=mCurrentStage->second) @@ -63,7 +68,7 @@ void CSMTools::Operation::verify() } else { - mCurrentStage->first->perform (mCurrentStep++); + mCurrentStage->first->perform (mCurrentStep++, messages); ++mCurrentStepTotal; break; } @@ -71,6 +76,9 @@ void CSMTools::Operation::verify() emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); + for (std::vector::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter) + emit reportMessage (iter->c_str(), mType); + if (mCurrentStage==mStages.end()) exit(); } \ No newline at end of file diff --git a/apps/opencs/model/tools/operation.hpp b/apps/opencs/model/tools/operation.hpp index 72419e00a..4731c58fa 100644 --- a/apps/opencs/model/tools/operation.hpp +++ b/apps/opencs/model/tools/operation.hpp @@ -39,6 +39,8 @@ namespace CSMTools void progress (int current, int max, int type); + void reportMessage (const QString& message, int type); + public slots: void abort(); diff --git a/apps/opencs/model/tools/stage.hpp b/apps/opencs/model/tools/stage.hpp index 912559410..1ad61960a 100644 --- a/apps/opencs/model/tools/stage.hpp +++ b/apps/opencs/model/tools/stage.hpp @@ -1,6 +1,9 @@ #ifndef CSM_TOOLS_STAGE_H #define CSM_TOOLS_STAGE_H +#include +#include + namespace CSMTools { class Stage @@ -12,7 +15,8 @@ namespace CSMTools virtual int setup() = 0; ///< \return number of steps - virtual void perform (int stage) = 0; + virtual void perform (int stage, std::vector& messages) = 0; + ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 608244a3c..8293b7291 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -30,6 +30,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (mVerifier, SIGNAL (finished()), this, SLOT (verifierDone())); + connect (mVerifier, SIGNAL (reportMessage (const QString&, int)), + this, SLOT (verifierMessage (const QString&, int))); } return mVerifier; @@ -77,4 +79,12 @@ int CSMTools::Tools::getRunningOperations() const void CSMTools::Tools::verifierDone() { emit done (CSMDoc::State_Verifying); +} + +#include +void CSMTools::Tools::verifierMessage (const QString& message, int type) +{ + /// \todo store it in a result model instead + + std::cout << message.toStdString() << std::endl; } \ No newline at end of file diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index ab1863738..04140bb91 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -43,6 +43,8 @@ namespace CSMTools void verifierDone(); + void verifierMessage (const QString& message, int type); + signals: void progress (int current, int max, int type); From 9fe7ff969047df565bae6b39045b6fb52fcf8b50 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 8 Dec 2012 23:27:59 +0100 Subject: [PATCH 058/916] added mandatory ID check stage --- apps/opencs/CMakeLists.txt | 2 ++ apps/opencs/model/doc/document.cpp | 1 + apps/opencs/model/doc/document.hpp | 5 ++- apps/opencs/model/tools/mandatoryid.cpp | 21 +++++++++++ apps/opencs/model/tools/mandatoryid.hpp | 38 ++++++++++++++++++++ apps/opencs/model/tools/operation.cpp | 4 +-- apps/opencs/model/tools/stage.hpp | 12 +++---- apps/opencs/model/tools/tools.cpp | 19 +++++++++- apps/opencs/model/tools/tools.hpp | 8 ++++- apps/opencs/model/world/universalid.cpp | 48 ++++++++++++++++++++++++- apps/opencs/model/world/universalid.hpp | 2 ++ 11 files changed, 148 insertions(+), 12 deletions(-) create mode 100644 apps/opencs/model/tools/mandatoryid.cpp create mode 100644 apps/opencs/model/tools/mandatoryid.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 381ce51cf..bad1e1376 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -8,6 +8,7 @@ set (OPENCS_SRC model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp + model/tools/mandatoryid.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp @@ -24,6 +25,7 @@ set (OPENCS_HDR model/world/commands.hpp model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp + model/tools/mandatoryid.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index d8ad5ff01..f03344e08 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,6 +2,7 @@ #include "document.hpp" CSMDoc::Document::Document (const std::string& name) +: mTools (mData) { mName = name; ///< \todo replace with ESX list diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 40f8c0ea1..f9d0a232c 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -22,10 +22,13 @@ namespace CSMDoc private: std::string mName; ///< \todo replace name with ESX list - QUndoStack mUndoStack; CSMWorld::Data mData; CSMTools::Tools mTools; + // 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. + QUndoStack mUndoStack; + int mSaveCount; ///< dummy implementation -> remove when proper save is implemented. QTimer mSaveTimer; ///< dummy implementation -> remove when proper save is implemented. diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp new file mode 100644 index 000000000..87ac77e67 --- /dev/null +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -0,0 +1,21 @@ + +#include "mandatoryid.hpp" + +#include "../world/idcollection.hpp" + +CSMTools::MandatoryIdStage::MandatoryIdStage (const CSMWorld::IdCollectionBase& idCollection, + const CSMWorld::UniversalId& collectionId, const std::vector& ids) +: mIdCollection (idCollection), mCollectionId (collectionId), mIds (ids) +{} + +int CSMTools::MandatoryIdStage::setup() +{ + return mIds.size(); +} + +void CSMTools::MandatoryIdStage::perform (int stage, std::vector& messages) +{ + if (mIdCollection.searchId (mIds.at (stage))==-1 || + mIdCollection.getRecord (mIds.at (stage)).isDeleted()) + messages.push_back (mCollectionId.toString() + " Missing mandatory record: " + mIds.at (stage)); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/mandatoryid.hpp b/apps/opencs/model/tools/mandatoryid.hpp new file mode 100644 index 000000000..14fcec204 --- /dev/null +++ b/apps/opencs/model/tools/mandatoryid.hpp @@ -0,0 +1,38 @@ +#ifndef CSM_TOOLS_MANDATORYID_H +#define CSM_TOOLS_MANDATORYID_H + +#include +#include + +#include "../world/universalid.hpp" + +#include "stage.hpp" + +namespace CSMWorld +{ + class IdCollectionBase; +} + +namespace CSMTools +{ + /// \brief Verify stage: make sure that records with specific IDs exist. + class MandatoryIdStage : public Stage + { + const CSMWorld::IdCollectionBase& mIdCollection; + CSMWorld::UniversalId mCollectionId; + std::vector mIds; + + public: + + MandatoryIdStage (const CSMWorld::IdCollectionBase& idCollection, const CSMWorld::UniversalId& collectionId, + const std::vector& ids); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/operation.cpp b/apps/opencs/model/tools/operation.cpp index b68f79ca4..71761cdae 100644 --- a/apps/opencs/model/tools/operation.cpp +++ b/apps/opencs/model/tools/operation.cpp @@ -19,8 +19,8 @@ void CSMTools::Operation::prepareStages() for (std::vector >::iterator iter (mStages.begin()); iter!=mStages.end(); ++iter) { - iter->second = mTotalSteps; - mTotalSteps += iter->first->setup(); + iter->second = iter->first->setup(); + mTotalSteps += iter->second; } } diff --git a/apps/opencs/model/tools/stage.hpp b/apps/opencs/model/tools/stage.hpp index 1ad61960a..3020936f3 100644 --- a/apps/opencs/model/tools/stage.hpp +++ b/apps/opencs/model/tools/stage.hpp @@ -8,15 +8,15 @@ namespace CSMTools { class Stage { - public: + public: - virtual ~Stage(); + virtual ~Stage(); - virtual int setup() = 0; - ///< \return number of steps + virtual int setup() = 0; + ///< \return number of steps - virtual void perform (int stage, std::vector& messages) = 0; - ///< Messages resulting from this tage will be appended to \a messages. + virtual void perform (int stage, std::vector& messages) = 0; + ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 8293b7291..a3cdb7822 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -7,6 +7,10 @@ #include "../doc/state.hpp" +#include "../world/data.hpp" + +#include "mandatoryid.hpp" + CSMTools::Operation *CSMTools::Tools::get (int type) { switch (type) @@ -32,12 +36,25 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() connect (mVerifier, SIGNAL (finished()), this, SLOT (verifierDone())); connect (mVerifier, SIGNAL (reportMessage (const QString&, int)), this, SLOT (verifierMessage (const QString&, int))); + + std::vector mandatoryIds; // I want C++11, damn it! + mandatoryIds.push_back ("Day"); + mandatoryIds.push_back ("DaysPassed"); + mandatoryIds.push_back ("GameHour"); + mandatoryIds.push_back ("Month"); + mandatoryIds.push_back ("PCRace"); + mandatoryIds.push_back ("PCVampire"); + mandatoryIds.push_back ("PCWerewolf"); + mandatoryIds.push_back ("PCYear"); + + mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), + CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); } return mVerifier; } -CSMTools::Tools::Tools() : mVerifier (0) +CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0) { } diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 04140bb91..da49fd8b8 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -3,6 +3,11 @@ #include +namespace CSMWorld +{ + class Data; +} + namespace CSMTools { class Verifier; @@ -12,6 +17,7 @@ namespace CSMTools { Q_OBJECT + CSMWorld::Data& mData; Verifier *mVerifier; // not implemented @@ -28,7 +34,7 @@ namespace CSMTools public: - Tools(); + Tools (CSMWorld::Data& data); virtual ~Tools(); diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index e2d8d1ffb..229779f5a 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -35,6 +35,52 @@ namespace }; } +CSMWorld::UniversalId::UniversalId (const std::string& universalId) +{ + std::string::size_type index = universalId.find (':'); + + if (index!=std::string::npos) + { + std::string type = universalId.substr (0, index); + + for (int i=0; sNoArg[i].mName; ++i) + if (type==sNoArg[i].mName) + { + mArgumentType = ArgumentType_None; + mType = sNoArg[i].mType; + mClass = sNoArg[i].mClass; + return; + } + + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mName) + { + mArgumentType = ArgumentType_Id; + mType = sIdArg[i].mType; + mClass = sIdArg[i].mClass; + mId = universalId.substr (0, index); + return; + } + + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mName) + { + mArgumentType = ArgumentType_Index; + mType = sIndexArg[i].mType; + mClass = sIndexArg[i].mClass; + + std::istringstream stream (universalId.substr (0, index)); + + if (stream >> mIndex) + return; + + break; + } + } + + throw std::runtime_error ("invalid UniversalId: " + universalId); +} + CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_None), mType (type), mIndex (0) { for (int i=0; sNoArg[i].mName; ++i) @@ -151,7 +197,7 @@ std::string CSMWorld::UniversalId::toString() const { std::ostringstream stream; - stream << getTypeName(); + stream << getTypeName() << ":"; switch (mArgumentType) { diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 6dc0eda1e..7b630ebc7 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -44,6 +44,8 @@ namespace CSMWorld public: + UniversalId (const std::string& universalId); + UniversalId (Type type = Type_None); ///< Using a type for a non-argument-less UniversalId will throw an exception. From 832fc56d34d06092bd6fc4344ca6fe71399b2205 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 9 Dec 2012 11:10:35 +0100 Subject: [PATCH 059/916] changed UniversalId to string conversion --- apps/opencs/model/tools/mandatoryid.cpp | 2 +- apps/opencs/model/world/universalid.cpp | 73 +++++++++++++------------ 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 87ac77e67..f9f2ca378 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -17,5 +17,5 @@ void CSMTools::MandatoryIdStage::perform (int stage, std::vector& m { if (mIdCollection.searchId (mIds.at (stage))==-1 || mIdCollection.getRecord (mIds.at (stage)).isDeleted()) - messages.push_back (mCollectionId.toString() + " Missing mandatory record: " + mIds.at (stage)); + messages.push_back (mCollectionId.toString() + "|Missing mandatory record: " + mIds.at (stage)); } \ No newline at end of file diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 229779f5a..98fb1d0b9 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -43,39 +43,44 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId) { std::string type = universalId.substr (0, index); - for (int i=0; sNoArg[i].mName; ++i) - if (type==sNoArg[i].mName) - { - mArgumentType = ArgumentType_None; - mType = sNoArg[i].mType; - mClass = sNoArg[i].mClass; - return; - } - - for (int i=0; sIdArg[i].mName; ++i) - if (type==sIdArg[i].mName) - { - mArgumentType = ArgumentType_Id; - mType = sIdArg[i].mType; - mClass = sIdArg[i].mClass; - mId = universalId.substr (0, index); - return; - } - - for (int i=0; sIndexArg[i].mName; ++i) - if (type==sIndexArg[i].mName) - { - mArgumentType = ArgumentType_Index; - mType = sIndexArg[i].mType; - mClass = sIndexArg[i].mClass; - - std::istringstream stream (universalId.substr (0, index)); - - if (stream >> mIndex) + if (index==std::string::npos) + { + for (int i=0; sNoArg[i].mName; ++i) + if (type==sNoArg[i].mName) + { + mArgumentType = ArgumentType_None; + mType = sNoArg[i].mType; + mClass = sNoArg[i].mClass; return; + } + } + else + { + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mName) + { + mArgumentType = ArgumentType_Id; + mType = sIdArg[i].mType; + mClass = sIdArg[i].mClass; + mId = universalId.substr (0, index); + return; + } - break; - } + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mName) + { + mArgumentType = ArgumentType_Index; + mType = sIndexArg[i].mType; + mClass = sIndexArg[i].mClass; + + std::istringstream stream (universalId.substr (0, index)); + + if (stream >> mIndex) + return; + + break; + } + } } throw std::runtime_error ("invalid UniversalId: " + universalId); @@ -197,13 +202,13 @@ std::string CSMWorld::UniversalId::toString() const { std::ostringstream stream; - stream << getTypeName() << ":"; + stream << getTypeName(); switch (mArgumentType) { case ArgumentType_None: break; - case ArgumentType_Id: stream << " " << mId; - case ArgumentType_Index: stream << " " << mIndex; + case ArgumentType_Id: stream << ": " << mId; + case ArgumentType_Index: stream << ": " << mIndex; } return stream.str(); From 0ed378dfb21fd3796f44a5ee0cd5542ca88e7af6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Dec 2012 11:24:30 +0100 Subject: [PATCH 060/916] changed sub view factory method signature --- apps/opencs/view/doc/view.cpp | 2 +- apps/opencs/view/world/subview.hpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 539b149cb..c1659b388 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -191,7 +191,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) if (iter==mSubViewFactories.end()) throw std::logic_error ("can't create subview for " + id.toString()); - CSVWorld::SubView *view = iter->second->makeSubView (id, mDocument->getData(), mDocument->getUndoStack()); + CSVWorld::SubView *view = iter->second->makeSubView (id, *mDocument); addDockWidget (Qt::TopDockWidgetArea, view); view->show(); } diff --git a/apps/opencs/view/world/subview.hpp b/apps/opencs/view/world/subview.hpp index 95448cb47..ff130828b 100644 --- a/apps/opencs/view/world/subview.hpp +++ b/apps/opencs/view/world/subview.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_SUBVIEW_H #define CSV_WORLD_SUBVIEW_H +#include "../../model/doc/document.hpp" + #include "../../model/world/universalid.hpp" #include @@ -35,21 +37,20 @@ namespace CSVWorld struct SubViewFactoryBase { - virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack) + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) = 0; }; template struct SubViewFactory : public SubViewFactoryBase { - virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); }; template - SubView *SubViewFactory::makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, - QUndoStack& undoStack) + SubView *SubViewFactory::makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) { - return new SubViewT (id, data, undoStack); + return new SubViewT (id, document.getData(), document.getUndoStack()); } template @@ -59,7 +60,7 @@ namespace CSVWorld SubViewFactoryWithCreateFlag (bool createAndDelete); - virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack); + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); }; template @@ -69,10 +70,9 @@ namespace CSVWorld template SubView *SubViewFactoryWithCreateFlag::makeSubView (const CSMWorld::UniversalId& id, - CSMWorld::Data& data, - QUndoStack& undoStack) + CSMDoc::Document& document) { - return new SubViewT (id, data, undoStack, mCreateAndDelete); + return new SubViewT (id, document.getData(), document.getUndoStack(), mCreateAndDelete); } } From 2db930a5cf36f19b174b8a1c8e1cdb6789ba6a14 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Dec 2012 13:22:43 +0100 Subject: [PATCH 061/916] rewrote subview factory system --- apps/opencs/CMakeLists.txt | 10 +-- apps/opencs/view/{world => doc}/subview.cpp | 4 +- apps/opencs/view/doc/subview.hpp | 41 +++++++++++ apps/opencs/view/doc/subviewfactory.cpp | 38 ++++++++++ apps/opencs/view/doc/subviewfactory.hpp | 55 ++++++++++++++ apps/opencs/view/doc/subviewfactoryimp.hpp | 50 +++++++++++++ apps/opencs/view/doc/view.cpp | 20 ++---- apps/opencs/view/doc/view.hpp | 9 +-- apps/opencs/view/world/subview.hpp | 79 --------------------- apps/opencs/view/world/subviews.cpp | 12 ++++ apps/opencs/view/world/subviews.hpp | 14 ++++ apps/opencs/view/world/tablesubview.cpp | 6 +- apps/opencs/view/world/tablesubview.hpp | 12 ++-- 13 files changed, 239 insertions(+), 111 deletions(-) rename apps/opencs/view/{world => doc}/subview.cpp (65%) create mode 100644 apps/opencs/view/doc/subview.hpp create mode 100644 apps/opencs/view/doc/subviewfactory.cpp create mode 100644 apps/opencs/view/doc/subviewfactory.hpp create mode 100644 apps/opencs/view/doc/subviewfactoryimp.hpp delete mode 100644 apps/opencs/view/world/subview.hpp create mode 100644 apps/opencs/view/world/subviews.cpp create mode 100644 apps/opencs/view/world/subviews.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bad1e1376..67cbcc772 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -10,9 +10,10 @@ set (OPENCS_SRC model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp model/tools/mandatoryid.cpp - view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp + view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp + view/doc/subview.cpp - view/world/subview.cpp view/world/table.cpp view/world/tablesubview.cpp + view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp ) set (OPENCS_HDR @@ -27,9 +28,10 @@ set (OPENCS_HDR model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp model/tools/mandatoryid.hpp - view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp + view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp + view/doc/subview.hpp view/doc/subviewfactoryimp.hpp - view/world/subview.hpp view/world/table.hpp view/world/tablesubview.hpp + view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp ) set (OPENCS_US diff --git a/apps/opencs/view/world/subview.cpp b/apps/opencs/view/doc/subview.cpp similarity index 65% rename from apps/opencs/view/world/subview.cpp rename to apps/opencs/view/doc/subview.cpp index 23f075980..1c356fa73 100644 --- a/apps/opencs/view/world/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -1,7 +1,7 @@ #include "subview.hpp" -CSVWorld::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) +CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) { /// \todo add a button to the title bar that clones this sub view @@ -12,7 +12,7 @@ CSVWorld::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) setMinimumHeight (60); } -CSMWorld::UniversalId CSVWorld::SubView::getUniversalId() const +CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const { return mUniversalId; } diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp new file mode 100644 index 000000000..50ec511ab --- /dev/null +++ b/apps/opencs/view/doc/subview.hpp @@ -0,0 +1,41 @@ +#ifndef CSV_DOC_SUBVIEW_H +#define CSV_DOC_SUBVIEW_H + +#include "../../model/doc/document.hpp" + +#include "../../model/world/universalid.hpp" + +#include "subviewfactory.hpp" + +#include + +class QUndoStack; + +namespace CSMWorld +{ + class Data; +} + +namespace CSVDoc +{ + class SubView : public QDockWidget + { + Q_OBJECT + + CSMWorld::UniversalId mUniversalId; + + // not implemented + SubView (const SubView&); + SubView& operator= (SubView&); + + public: + + SubView (const CSMWorld::UniversalId& id); + + CSMWorld::UniversalId getUniversalId() const; + + virtual void setEditLock (bool locked) = 0; + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/subviewfactory.cpp b/apps/opencs/view/doc/subviewfactory.cpp new file mode 100644 index 000000000..8576f6b1d --- /dev/null +++ b/apps/opencs/view/doc/subviewfactory.cpp @@ -0,0 +1,38 @@ + +#include "subviewfactory.hpp" + +#include + +#include + +CSVDoc::SubViewFactoryBase::SubViewFactoryBase() {} + +CSVDoc::SubViewFactoryBase::~SubViewFactoryBase() {} + + +CSVDoc::SubViewFactoryManager::SubViewFactoryManager() {} + +CSVDoc::SubViewFactoryManager::~SubViewFactoryManager() +{ + for (std::map::iterator iter (mSubViewFactories.begin()); + iter!=mSubViewFactories.end(); ++iter) + delete iter->second; +} + +void CSVDoc::SubViewFactoryManager::add (const CSMWorld::UniversalId::Type& id, SubViewFactoryBase *factory) +{ + assert (mSubViewFactories.find (id)==mSubViewFactories.end()); + + mSubViewFactories.insert (std::make_pair (id, factory)); +} + +CSVDoc::SubView *CSVDoc::SubViewFactoryManager::makeSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document) +{ + std::map::iterator iter = mSubViewFactories.find (id.getType()); + + if (iter==mSubViewFactories.end()) + throw std::runtime_error ("Failed to create a sub view for: " + id.toString()); + + return iter->second->makeSubView (id, document); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/subviewfactory.hpp b/apps/opencs/view/doc/subviewfactory.hpp new file mode 100644 index 000000000..1f7c15480 --- /dev/null +++ b/apps/opencs/view/doc/subviewfactory.hpp @@ -0,0 +1,55 @@ +#ifndef CSV_DOC_SUBVIEWFACTORY_H +#define CSV_DOC_SUBVIEWFACTORY_H + +#include + +#include "../../model/world/universalid.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVDoc +{ + class SubView; + + class SubViewFactoryBase + { + // not implemented + SubViewFactoryBase (const SubViewFactoryBase&); + SubViewFactoryBase& operator= (const SubViewFactoryBase&); + + public: + + SubViewFactoryBase(); + + virtual ~SubViewFactoryBase(); + + virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) = 0; + ///< The ownership of the returned sub view is not transferred. + }; + + class SubViewFactoryManager + { + std::map mSubViewFactories; + + // not implemented + SubViewFactoryManager (const SubViewFactoryManager&); + SubViewFactoryManager& operator= (const SubViewFactoryManager&); + + public: + + SubViewFactoryManager(); + + ~SubViewFactoryManager(); + + void add (const CSMWorld::UniversalId::Type& id, SubViewFactoryBase *factory); + ///< The ownership of \a factory is transferred to this. + + SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + ///< The ownership of the returned sub view is not transferred. + }; +} + +#endif diff --git a/apps/opencs/view/doc/subviewfactoryimp.hpp b/apps/opencs/view/doc/subviewfactoryimp.hpp new file mode 100644 index 000000000..d16e0b2b7 --- /dev/null +++ b/apps/opencs/view/doc/subviewfactoryimp.hpp @@ -0,0 +1,50 @@ +#ifndef CSV_DOC_SUBVIEWFACTORYIMP_H +#define CSV_DOC_SUBVIEWFACTORYIMP_H + +#include "../../model/doc/document.hpp" + +#include "subviewfactory.hpp" + +namespace CSVDoc +{ + template + class SubViewFactory : public SubViewFactoryBase + { + public: + + virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + }; + + template + CSVDoc::SubView *SubViewFactory::makeSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document) + { + return new SubViewT (id, document); + } + + template + class SubViewFactoryWithCreateFlag : public SubViewFactoryBase + { + bool mCreateAndDelete; + + public: + + SubViewFactoryWithCreateFlag (bool createAndDelete); + + virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + }; + + template + SubViewFactoryWithCreateFlag::SubViewFactoryWithCreateFlag (bool createAndDelete) + : mCreateAndDelete (createAndDelete) + {} + + template + CSVDoc::SubView *SubViewFactoryWithCreateFlag::makeSubView (const CSMWorld::UniversalId& id, + CSMDoc::Document& document) + { + return new SubViewT (id, document, mCreateAndDelete); + } +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index c1659b388..47053192b 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -10,10 +10,11 @@ #include "../../model/doc/document.hpp" -#include "../world/tablesubview.hpp" +#include "../world/subviews.hpp" #include "viewmanager.hpp" #include "operations.hpp" +#include "subview.hpp" void CSVDoc::View::closeEvent (QCloseEvent *event) { @@ -120,15 +121,11 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to setupUi(); - mSubViewFactories.insert (std::make_pair (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), - new CSVWorld::SubViewFactoryWithCreateFlag (true))); + CSVWorld::addSubViewFactories (mSubViewFactory); } CSVDoc::View::~View() { - for (std::map::iterator iter (mSubViewFactories.begin()); - iter!=mSubViewFactories.end(); ++iter) - delete iter->second; } const CSMDoc::Document *CSVDoc::View::getDocument() const @@ -165,9 +162,9 @@ void CSVDoc::View::updateDocumentState() if (!(state & operations[i])) mOperations->quitOperation (operations[i]); - QList subViews = findChildren(); + QList subViews = findChildren(); - for (QList::iterator iter (subViews.begin()); iter!=subViews.end(); ++iter) + for (QList::iterator iter (subViews.begin()); iter!=subViews.end(); ++iter) (*iter)->setEditLock (state & CSMDoc::State_Locked); } @@ -186,12 +183,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) - std::map::iterator iter = mSubViewFactories.find (id); - - if (iter==mSubViewFactories.end()) - throw std::logic_error ("can't create subview for " + id.toString()); - - CSVWorld::SubView *view = iter->second->makeSubView (id, *mDocument); + SubView *view = mSubViewFactory.makeSubView (id, *mDocument); addDockWidget (Qt::TopDockWidgetArea, view); view->show(); } diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index c86c3b362..f7d4dd373 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -6,6 +6,8 @@ #include +#include "subviewfactory.hpp" + class QAction; namespace CSMDoc @@ -18,11 +20,6 @@ namespace CSMWorld class UniversalId; } -namespace CSVWorld -{ - struct SubViewFactoryBase; -} - namespace CSVDoc { class ViewManager; @@ -42,7 +39,7 @@ namespace CSVDoc QAction *mVerify; std::vector mEditingActions; Operations *mOperations; - std::map mSubViewFactories; + SubViewFactoryManager mSubViewFactory; // not implemented View (const View&); diff --git a/apps/opencs/view/world/subview.hpp b/apps/opencs/view/world/subview.hpp deleted file mode 100644 index ff130828b..000000000 --- a/apps/opencs/view/world/subview.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef CSV_WORLD_SUBVIEW_H -#define CSV_WORLD_SUBVIEW_H - -#include "../../model/doc/document.hpp" - -#include "../../model/world/universalid.hpp" - -#include - -class QUndoStack; - -namespace CSMWorld -{ - class Data; -} - -namespace CSVWorld -{ - class SubView : public QDockWidget - { - Q_OBJECT - - CSMWorld::UniversalId mUniversalId; - - // not implemented - SubView (const SubView&); - SubView& operator= (SubView&); - - public: - - SubView (const CSMWorld::UniversalId& id); - - CSMWorld::UniversalId getUniversalId() const; - - virtual void setEditLock (bool locked) = 0; - }; - - struct SubViewFactoryBase - { - virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) - = 0; - }; - - template - struct SubViewFactory : public SubViewFactoryBase - { - virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); - }; - - template - SubView *SubViewFactory::makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) - { - return new SubViewT (id, document.getData(), document.getUndoStack()); - } - - template - struct SubViewFactoryWithCreateFlag : public SubViewFactoryBase - { - bool mCreateAndDelete; - - SubViewFactoryWithCreateFlag (bool createAndDelete); - - virtual SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); - }; - - template - SubViewFactoryWithCreateFlag::SubViewFactoryWithCreateFlag (bool createAndDelete) - : mCreateAndDelete (createAndDelete) - {} - - template - SubView *SubViewFactoryWithCreateFlag::makeSubView (const CSMWorld::UniversalId& id, - CSMDoc::Document& document) - { - return new SubViewT (id, document.getData(), document.getUndoStack(), mCreateAndDelete); - } -} - -#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp new file mode 100644 index 000000000..fdc0cb31d --- /dev/null +++ b/apps/opencs/view/world/subviews.cpp @@ -0,0 +1,12 @@ + +#include "subviews.hpp" + +#include "../doc/subviewfactoryimp.hpp" + +#include "tablesubview.hpp" + +void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) +{ + manager.add (CSMWorld::UniversalId::Type_Globals, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); +} \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.hpp b/apps/opencs/view/world/subviews.hpp new file mode 100644 index 000000000..51e4cb083 --- /dev/null +++ b/apps/opencs/view/world/subviews.hpp @@ -0,0 +1,14 @@ +#ifndef CSV_WORLD_SUBVIEWS_H +#define CSV_WORLD_SUBVIEWS_H + +namespace CSVDoc +{ + class SubViewFactoryManager; +} + +namespace CSVWorld +{ + void addSubViewFactories (CSVDoc::SubViewFactoryManager& manager); +} + +#endif diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 3bc555a2d..4abd531d0 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -1,13 +1,15 @@ #include "tablesubview.hpp" +#include "../../model/doc/document.hpp" + #include "table.hpp" -CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, +CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete) : SubView (id) { - setWidget (mTable = new Table (id, data, undoStack, createAndDelete)); + setWidget (mTable = new Table (id, document.getData(), document.getUndoStack(), createAndDelete)); } void CSVWorld::TableSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index b45b3c279..9b0785c47 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -1,22 +1,26 @@ #ifndef CSV_WORLD_TABLESUBVIEW_H #define CSV_WORLD_TABLESUBVIEW_H -#include "subview.hpp" +#include "../doc/subview.hpp" class QUndoStack; +namespace CSMDoc +{ + class Document; +} + namespace CSVWorld { class Table; - class TableSubView : public SubView + class TableSubView : public CSVDoc::SubView { Table *mTable; public: - TableSubView (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, - bool createAndDelete); + TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); virtual void setEditLock (bool locked); }; From c75563c184de28aca46ae2cfb52a4318771cfa1e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 11 Dec 2012 15:35:47 +0100 Subject: [PATCH 062/916] report model and view --- apps/opencs/CMakeLists.txt | 8 ++- apps/opencs/model/doc/document.cpp | 10 +++- apps/opencs/model/doc/document.hpp | 7 ++- apps/opencs/model/tools/reportmodel.cpp | 66 ++++++++++++++++++++++++ apps/opencs/model/tools/reportmodel.hpp | 35 +++++++++++++ apps/opencs/model/tools/tools.cpp | 28 +++++++--- apps/opencs/model/tools/tools.hpp | 13 ++++- apps/opencs/model/world/idtable.cpp | 2 +- apps/opencs/model/world/universalid.cpp | 3 +- apps/opencs/model/world/universalid.hpp | 5 +- apps/opencs/view/doc/view.cpp | 5 +- apps/opencs/view/tools/reportsubview.cpp | 25 +++++++++ apps/opencs/view/tools/reportsubview.hpp | 29 +++++++++++ apps/opencs/view/tools/subviews.cpp | 12 +++++ apps/opencs/view/tools/subviews.hpp | 14 +++++ 15 files changed, 246 insertions(+), 16 deletions(-) create mode 100644 apps/opencs/model/tools/reportmodel.cpp create mode 100644 apps/opencs/model/tools/reportmodel.hpp create mode 100644 apps/opencs/view/tools/reportsubview.cpp create mode 100644 apps/opencs/view/tools/reportsubview.hpp create mode 100644 apps/opencs/view/tools/subviews.cpp create mode 100644 apps/opencs/view/tools/subviews.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 67cbcc772..1f9fe85a2 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -8,12 +8,14 @@ set (OPENCS_SRC model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp - model/tools/mandatoryid.cpp + model/tools/mandatoryid.cpp model/tools/reportmodel.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp view/doc/subview.cpp view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp + + view/tools/reportsubview.cpp view/tools/subviews.cpp ) set (OPENCS_HDR @@ -26,12 +28,14 @@ set (OPENCS_HDR model/world/commands.hpp model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp - model/tools/mandatoryid.hpp + model/tools/mandatoryid.hpp model/tools/reportmodel.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp view/doc/subview.hpp view/doc/subviewfactoryimp.hpp view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp + + view/tools/reportsubview.hpp view/tools/subviews.hpp ) set (OPENCS_US diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index f03344e08..9d2694483 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -50,10 +50,11 @@ void CSMDoc::Document::save() emit progress (1, 16, State_Saving, 1, this); } -void CSMDoc::Document::verify() +CSMWorld::UniversalId CSMDoc::Document::verify() { - mTools.runVerifier(); + CSMWorld::UniversalId id = mTools.runVerifier(); emit stateChanged (getState(), this); + return id; } void CSMDoc::Document::abortOperation (int type) @@ -102,6 +103,11 @@ CSMWorld::Data& CSMDoc::Document::getData() return mData; } +CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId& id) +{ + return mTools.getReport (id); +} + void CSMDoc::Document::progress (int current, int max, int type) { emit progress (current, max, type, 1, this); diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index f9d0a232c..43e8bba37 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -13,6 +13,8 @@ #include "state.hpp" +class QAbstractItemModel; + namespace CSMDoc { class Document : public QObject @@ -50,7 +52,7 @@ namespace CSMDoc void save(); - void verify(); + CSMWorld::UniversalId verify(); void abortOperation (int type); @@ -58,6 +60,9 @@ namespace CSMDoc CSMWorld::Data& getData(); + CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id); + ///< The ownership of the returned report is not transferred. + signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp new file mode 100644 index 000000000..f142d7669 --- /dev/null +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -0,0 +1,66 @@ + +#include "reportmodel.hpp" + +#include + +int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return mRows.size(); +} + +int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const +{ + if (parent.isValid()) + return 0; + + return 2; +} + +QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const +{ + if (role!=Qt::DisplayRole) + return QVariant(); + + if (index.column()==0) + return static_cast (mRows.at (index.row()).first.getType()); + else + return mRows.at (index.row()).second.c_str(); +} + +QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const +{ + if (role!=Qt::DisplayRole) + return QVariant(); + + if (orientation==Qt::Vertical) + return QVariant(); + + return tr (section==0 ? "Type" : "Description"); +} + +bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent) +{ + if (parent.isValid()) + return false; + + mRows.erase (mRows.begin()+row, mRows.begin()+row+count); + + return true; +} + +void CSMTools::ReportModel::add (const std::string& row) +{ + std::string::size_type index = row.find ('|'); + + if (index==std::string::npos) + throw std::logic_error ("invalid report message"); + + beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); + + mRows.push_back (std::make_pair (row.substr (0, index), row.substr (index+1))); + + endInsertRows(); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp new file mode 100644 index 000000000..8814b6d49 --- /dev/null +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -0,0 +1,35 @@ +#ifndef CSM_TOOLS_REPORTMODEL_H +#define CSM_TOOLS_REPORTMODEL_H + +#include +#include + +#include + +#include "../world/universalid.hpp" + +namespace CSMTools +{ + class ReportModel : public QAbstractTableModel + { + Q_OBJECT + + std::vector > mRows; + + public: + + virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; + + virtual int columnCount (const QModelIndex & parent = QModelIndex()) const; + + virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + + void add (const std::string& row); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index a3cdb7822..8dd1c0fe6 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -8,7 +8,9 @@ #include "../doc/state.hpp" #include "../world/data.hpp" +#include "../world/universalid.hpp" +#include "reportmodel.hpp" #include "mandatoryid.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) @@ -54,9 +56,10 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() return mVerifier; } -CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0) +CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0), mNextReportNumber (0) { - + for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) + delete iter->second; } CSMTools::Tools::~Tools() @@ -64,9 +67,14 @@ CSMTools::Tools::~Tools() delete mVerifier; } -void CSMTools::Tools::runVerifier() +CSMWorld::UniversalId CSMTools::Tools::runVerifier() { + mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); + mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1; + getVerifier()->start(); + + return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); } void CSMTools::Tools::abortOperation (int type) @@ -93,15 +101,23 @@ int CSMTools::Tools::getRunningOperations() const return result; } +CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id) +{ + if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults) + throw std::logic_error ("invalid request for report model: " + id.toString()); + + return mReports.at (id.getIndex()); +} + void CSMTools::Tools::verifierDone() { emit done (CSMDoc::State_Verifying); } -#include void CSMTools::Tools::verifierMessage (const QString& message, int type) { - /// \todo store it in a result model instead + std::map::iterator iter = mActiveReports.find (type); - std::cout << message.toStdString() << std::endl; + if (iter!=mActiveReports.end()) + mReports[iter->second]->add (message.toStdString()); } \ No newline at end of file diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index da49fd8b8..652345c6d 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -3,15 +3,19 @@ #include +#include + namespace CSMWorld { class Data; + class UniversalId; } namespace CSMTools { class Verifier; class Operation; + class ReportModel; class Tools : public QObject { @@ -19,6 +23,9 @@ namespace CSMTools CSMWorld::Data& mData; Verifier *mVerifier; + std::map mReports; + int mNextReportNumber; + std::map mActiveReports; // type, report number // not implemented Tools (const Tools&); @@ -38,13 +45,17 @@ namespace CSMTools virtual ~Tools(); - void runVerifier(); + CSMWorld::UniversalId runVerifier(); + ///< \return ID of the report for this verification run void abortOperation (int type); ///< \attention The operation is not aborted immediately. int getRunningOperations() const; + ReportModel *getReport (const CSMWorld::UniversalId& id); + ///< The ownership of the returned report is not transferred. + private slots: void verifierDone(); diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index a2b0a3c1f..3fe1fadfe 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -35,7 +35,7 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const return QVariant(); if (role==Qt::EditRole && !mIdCollection->isEditable (index.column())) - return QVariant(); + return QVariant(); return mIdCollection->getData (index.row(), index.column()); } diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 98fb1d0b9..81561bcf4 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -30,6 +30,7 @@ namespace static const TypeData sIndexArg[] = { + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -39,7 +40,7 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId) { std::string::size_type index = universalId.find (':'); - if (index!=std::string::npos) + if (index==std::string::npos) { std::string type = universalId.substr (0, index); diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 7b630ebc7..14c086510 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -31,7 +31,10 @@ namespace CSMWorld enum Type { Type_None, - Type_Globals + + Type_Globals, + + Type_VerificationResults }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 47053192b..4ffd9d749 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -12,6 +12,8 @@ #include "../world/subviews.hpp" +#include "../tools/subviews.hpp" + #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -122,6 +124,7 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to setupUi(); CSVWorld::addSubViewFactories (mSubViewFactory); + CSVTools::addSubViewFactories (mSubViewFactory); } CSVDoc::View::~View() @@ -200,7 +203,7 @@ void CSVDoc::View::save() void CSVDoc::View::verify() { - mDocument->verify(); + addSubView (mDocument->verify()); } void CSVDoc::View::addGlobalsSubView() diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp new file mode 100644 index 000000000..3c9283684 --- /dev/null +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -0,0 +1,25 @@ + +#include "reportsubview.hpp" + +#include +#include + +#include "../../model/tools/reportmodel.hpp" + +CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: CSVDoc::SubView (id) +{ + setWidget (mTable = new QTableView (this)); + mTable->setModel (document.getReport (id)); + + mTable->horizontalHeader()->setResizeMode (QHeaderView::Interactive); + mTable->verticalHeader()->hide(); + mTable->setSortingEnabled (true); + mTable->setSelectionBehavior (QAbstractItemView::SelectRows); + mTable->setSelectionMode (QAbstractItemView::ExtendedSelection); +} + +void CSVTools::ReportSubView::setEditLock (bool locked) +{ + // ignored. We don't change document state anyway. +} \ No newline at end of file diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp new file mode 100644 index 000000000..f81f3c386 --- /dev/null +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -0,0 +1,29 @@ +#ifndef CSV_TOOLS_REPORTSUBVIEW_H +#define CSV_TOOLS_REPORTSUBVIEW_H + +#include "../doc/subview.hpp" + +class QTableView; + +namespace CSMDoc +{ + class Document; +} + +namespace CSVTools +{ + class Table; + + class ReportSubView : public CSVDoc::SubView + { + QTableView *mTable; + + public: + + ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp new file mode 100644 index 000000000..781cf602e --- /dev/null +++ b/apps/opencs/view/tools/subviews.cpp @@ -0,0 +1,12 @@ + +#include "subviews.hpp" + +#include "../doc/subviewfactoryimp.hpp" + +#include "reportsubview.hpp" + +void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) +{ + manager.add (CSMWorld::UniversalId::Type_VerificationResults, + new CSVDoc::SubViewFactory); +} \ No newline at end of file diff --git a/apps/opencs/view/tools/subviews.hpp b/apps/opencs/view/tools/subviews.hpp new file mode 100644 index 000000000..1bac32228 --- /dev/null +++ b/apps/opencs/view/tools/subviews.hpp @@ -0,0 +1,14 @@ +#ifndef CSV_TOOLS_SUBVIEWS_H +#define CSV_TOOLS_SUBVIEWS_H + +namespace CSVDoc +{ + class SubViewFactoryManager; +} + +namespace CSVTools +{ + void addSubViewFactories (CSVDoc::SubViewFactoryManager& manager); +} + +#endif From c49966dd29c61f0f5e1bf26348e5e24a0cf25785 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 11 Dec 2012 22:49:31 +0100 Subject: [PATCH 063/916] started over --- CMakeLists.txt | 4 + apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/videoplayer.cpp | 1177 +++++++++++++-------- apps/openmw/mwrender/videoplayer.hpp | 231 ++-- cmake/FindSDL.cmake | 177 ++++ 5 files changed, 1073 insertions(+), 518 deletions(-) create mode 100644 cmake/FindSDL.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c11fda9f4..084363da7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,10 @@ if (USE_MPG123) set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123) endif (USE_MPG123) +find_package (SDL REQUIRED) +set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${SDL_INCLUDE_DIR}) +set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${SDL_LIBRARY}) + # Platform specific if (WIN32) set(Boost_USE_STATIC_LIBS ON) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a1a24b7ba..5663ded09 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -928,7 +928,7 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend void RenderingManager::playVideo(const std::string& name) { - mVideoPlayer->play ("video/" + name); + mVideoPlayer->playVideo ("video/" + name); } } // namespace diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b1fee213f..3ddc7961c 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1,153 +1,788 @@ #include "videoplayer.hpp" -//#ifdef OPENMW_USE_FFMPEG - -#include -#include -#include -#include - - -extern "C" -{ -#include -#include -#include -} #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" -#define MIN_QUEUED_PACKETS 30 - namespace MWRender { int OgreResource_Read(void *opaque, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); - int num_read = stream->size() - stream->tell(); + int num_read = stream->size() - stream->tell(); - if (num_read > buf_size) - num_read = buf_size; + if (num_read > buf_size) + num_read = buf_size; - stream->read(buf, num_read); - return num_read; + stream->read(buf, num_read); + return num_read; } int OgreResource_Write(void *opaque, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); - int num_write = stream->size() - stream->tell(); + int num_write = stream->size() - stream->tell(); - if (num_write > buf_size) - num_write = buf_size; + if (num_write > buf_size) + num_write = buf_size; - stream->write (buf, num_write); - return num_write; + stream->write (buf, num_write); + return num_write; } int64_t OgreResource_Seek(void *opaque, int64_t offset, int whence) { - Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); - switch (whence) - { - case SEEK_SET: - stream->seek(offset); - case SEEK_CUR: - stream->seek(stream->tell() + offset); - case SEEK_END: - stream->seek(stream->size() + offset); - case AVSEEK_SIZE: - return stream->size(); - default: - return -1; - } + switch (whence) + { + case SEEK_SET: + stream->seek(offset); + case SEEK_CUR: + stream->seek(stream->tell() + offset); + case SEEK_END: + stream->seek(stream->size() + offset); + case AVSEEK_SIZE: + return stream->size(); + default: + return -1; + } - return stream->tell(); + return stream->tell(); } - //------------------------------------------------------------------------------------------- - AVPacketQueue::AVPacketQueue(): - mFirstPacket(NULL), mLastPacket(NULL), mNumPackets(0), mSize(0) - { + + /* Since we only have one decoding thread, the Big Struct + can be global in case we need it. */ + VideoState *global_video_state; + + void packet_queue_init(PacketQueue *q) { + memset(q, 0, sizeof(PacketQueue)); } - - int AVPacketQueue::put(AVPacket* pkt) - { - if(av_dup_packet(pkt) < 0) - { + int packet_queue_put(PacketQueue *q, AVPacket *pkt) { + AVPacketList *pkt1; + if(av_dup_packet(pkt) < 0) { return -1; } - - AVPacketList* pkt1; pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); - if (pkt1 == NULL) return -1; + if (!pkt1) + return -1; pkt1->pkt = *pkt; pkt1->next = NULL; - if (mLastPacket == NULL) mFirstPacket = pkt1; - else mLastPacket->next = pkt1; + q->mutex.lock (); - mLastPacket = pkt1; - mNumPackets++; - mSize += pkt1->pkt.size; + if (!q->last_pkt) + q->first_pkt = pkt1; + else + q->last_pkt->next = pkt1; + q->last_pkt = pkt1; + q->nb_packets++; + q->size += pkt1->pkt.size; + q->cond.notify_one(); + q->mutex.unlock (); + return 0; + } + static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) { + AVPacketList *pkt1; + int ret; + + boost::unique_lock lock(q->mutex); + + for(;;) { + + if(global_video_state->quit) { + ret = -1; + break; + } + + pkt1 = q->first_pkt; + if (pkt1) { + q->first_pkt = pkt1->next; + if (!q->first_pkt) + q->last_pkt = NULL; + q->nb_packets--; + q->size -= pkt1->pkt.size; + *pkt = pkt1->pkt; + av_free(pkt1); + ret = 1; + break; + } else if (!block) { + ret = 0; + break; + } else { + + + q->cond.wait(lock); + } + } + return ret; + } + static void packet_queue_flush(PacketQueue *q) { + AVPacketList *pkt, *pkt1; + + q->mutex.lock(); + for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) { + pkt1 = pkt->next; + av_free_packet(&pkt->pkt); + av_freep(&pkt); + } + q->last_pkt = NULL; + q->first_pkt = NULL; + q->nb_packets = 0; + q->size = 0; + q->mutex.unlock (); + } + double get_audio_clock(VideoState *is) { + double pts; + int hw_buf_size, bytes_per_sec, n; + + pts = is->audio_clock; /* maintained in the audio thread */ + hw_buf_size = is->audio_buf_size - is->audio_buf_index; + bytes_per_sec = 0; + n = is->audio_st->codec->channels * 2; + if(is->audio_st) { + bytes_per_sec = is->audio_st->codec->sample_rate * n; + } + if(bytes_per_sec) { + pts -= (double)hw_buf_size / bytes_per_sec; + } + return pts; + } + double get_video_clock(VideoState *is) { + double delta; + + delta = (av_gettime() - is->video_current_pts_time) / 1000000.0; + return is->video_current_pts + delta; + } + double get_external_clock(VideoState *is) { + return av_gettime() / 1000000.0; + } + double get_master_clock(VideoState *is) { + if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) { + return get_video_clock(is); + } else if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) { + return get_audio_clock(is); + } else { + return get_external_clock(is); + } + } + /* Add or subtract samples to get a better sync, return new + audio buffer size */ + int synchronize_audio(VideoState *is, short *samples, + int samples_size, double pts) { + int n; + double ref_clock; + + n = 2 * is->audio_st->codec->channels; + + if(is->av_sync_type != AV_SYNC_AUDIO_MASTER) { + double diff, avg_diff; + int wanted_size, min_size, max_size; + // int nb_samples; + + ref_clock = get_master_clock(is); + diff = get_audio_clock(is) - ref_clock; + if(diff < AV_NOSYNC_THRESHOLD) { + // accumulate the diffs + is->audio_diff_cum = diff + is->audio_diff_avg_coef + * is->audio_diff_cum; + if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) { + is->audio_diff_avg_count++; + } else { + avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); + if(fabs(avg_diff) >= is->audio_diff_threshold) { + wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); + min_size = samples_size * ((100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100); + max_size = samples_size * ((100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100); + if(wanted_size < min_size) { + wanted_size = min_size; + } else if (wanted_size > max_size) { + wanted_size = max_size; + } + if(wanted_size < samples_size) { + /* remove samples */ + samples_size = wanted_size; + } else if(wanted_size > samples_size) { + uint8_t *samples_end, *q; + int nb; + /* add samples by copying final sample*/ + nb = (samples_size - wanted_size); + samples_end = (uint8_t *)samples + samples_size - n; + q = samples_end + n; + while(nb > 0) { + memcpy(q, samples_end, n); + q += n; + nb -= n; + } + samples_size = wanted_size; + } + } + } + } else { + /* difference is TOO big; reset diff stuff */ + is->audio_diff_avg_count = 0; + is->audio_diff_cum = 0; + } + } + return samples_size; + } + int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size, double *pts_ptr) { + int len1, data_size, n; + AVPacket *pkt = &is->audio_pkt; + double pts; + + for(;;) { + while(is->audio_pkt_size > 0) { + data_size = buf_size; + len1 = avcodec_decode_audio3(is->audio_st->codec, + (int16_t *)audio_buf, &data_size, pkt); + + + if(len1 < 0) { + /* if error, skip frame */ + is->audio_pkt_size = 0; + break; + } + is->audio_pkt_data += len1; + is->audio_pkt_size -= len1; + if(data_size <= 0) { + /* No data yet, get more frames */ + continue; + } + pts = is->audio_clock; + *pts_ptr = pts; + n = 2 * is->audio_st->codec->channels; + is->audio_clock += (double)data_size / + (double)(n * is->audio_st->codec->sample_rate); + + /* We have data, return it and come back for more later */ + return data_size; + } + if(pkt->data) + av_free_packet(pkt); + + if(is->quit) { + return -1; + } + /* next packet */ + if(packet_queue_get(&is->audioq, pkt, 1) < 0) { + return -1; + } + is->audio_pkt_data = pkt->data; + is->audio_pkt_size = pkt->size; + /* if update, update the audio clock w/pts */ + if(pkt->pts != AV_NOPTS_VALUE) { + is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; + } + } + } + + void audio_callback(void *userdata, Uint8 *stream, int len) { + VideoState *is = (VideoState *)userdata; + int len1, audio_size; + double pts; + + while(len > 0) { + if(is->audio_buf_index >= is->audio_buf_size) { + /* We have already sent all our data; get more */ + audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts); + if(audio_size < 0) { + /* If error, output silence */ + is->audio_buf_size = 1024; + memset(is->audio_buf, 0, is->audio_buf_size); + } else { + audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, + audio_size, pts); + is->audio_buf_size = audio_size; + } + is->audio_buf_index = 0; + } + len1 = is->audio_buf_size - is->audio_buf_index; + if(len1 > len) + len1 = len; + memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1); + len -= len1; + stream += len1; + is->audio_buf_index += len1; + } + } + + /* + static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) { + SDL_Event event; + event.type = FF_REFRESH_EVENT; + event.user.data1 = opaque; + SDL_PushEvent(&event); + return 0; // 0 means stop timer + } + */ + + void timer_callback (int delay, VideoState* is) + { + boost::this_thread::sleep (boost::posix_time::milliseconds(delay)); + is->refresh++; + } + + /* schedule a video refresh in 'delay' ms */ + static void schedule_refresh(VideoState *is, int delay) + { + //SDL_AddTimer(delay, sdl_refresh_timer_cb, is); + //is->refresh_queue.push_back (delay); + + boost::thread (boost::bind(&timer_callback, delay, is)); + } + + void video_display(VideoState *is) + { + VideoPicture *vp; + + vp = &is->pictq[is->pictq_rindex]; + + if (is->video_st->codec->width != 0 && is->video_st->codec->height != 0) + { + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().getByName("VideoTexture"); + if (texture.isNull () || texture->getWidth() != is->video_st->codec->width || texture->getHeight() != is->video_st->codec->height) + { + Ogre::TextureManager::getSingleton ().remove ("VideoTexture"); + texture = Ogre::TextureManager::getSingleton().createManual( + "VideoTexture", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + is->video_st->codec->width, is->video_st->codec->height, + 0, + Ogre::PF_BYTE_RGBA, + Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + } + Ogre::PixelBox pb(is->video_st->codec->width, is->video_st->codec->height, 1, Ogre::PF_BYTE_RGBA, vp->data); + Ogre::HardwarePixelBufferSharedPtr buffer = texture->getBuffer(); + buffer->blitFromMemory(pb); + } + + free(vp->data); + } + + + void video_refresh_timer(void *userdata) { + + VideoState *is = (VideoState *)userdata; + VideoPicture *vp; + double actual_delay, delay, sync_threshold, ref_clock, diff; + + if(is->video_st) { + if(is->pictq_size == 0) { + schedule_refresh(is, 1); + } else { + vp = &is->pictq[is->pictq_rindex]; + + is->video_current_pts = vp->pts; + is->video_current_pts_time = av_gettime(); + + delay = vp->pts - is->frame_last_pts; /* the pts from last time */ + if(delay <= 0 || delay >= 1.0) { + /* if incorrect delay, use previous one */ + delay = is->frame_last_delay; + } + /* save for next time */ + is->frame_last_delay = delay; + is->frame_last_pts = vp->pts; + + /* update delay to sync to audio if not master source */ + if(is->av_sync_type != AV_SYNC_VIDEO_MASTER) { + ref_clock = get_master_clock(is); + diff = vp->pts - ref_clock; + + /* Skip or repeat the frame. Take delay into account + FFPlay still doesn't "know if this is the best guess." */ + sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; + if(fabs(diff) < AV_NOSYNC_THRESHOLD) { + if(diff <= -sync_threshold) { + delay = 0; + } else if(diff >= sync_threshold) { + delay = 2 * delay; + } + } + } + + is->frame_timer += delay; + /* computer the REAL delay */ + actual_delay = is->frame_timer - (av_gettime() / 1000000.0); + if(actual_delay < 0.010) { + /* Really it should skip the picture instead */ + actual_delay = 0.010; + } + schedule_refresh(is, (int)(actual_delay * 1000 + 0.5)); + + /* show the picture! */ + video_display(is); + + /* update queue for next picture! */ + if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) { + is->pictq_rindex = 0; + } + is->pictq_mutex.lock(); + is->pictq_size--; + is->pictq_cond.notify_one (); + is->pictq_mutex.unlock (); + } + } else { + schedule_refresh(is, 100); + } + } + + int queue_picture(VideoState *is, AVFrame *pFrame, double pts) { + + VideoPicture *vp; + + /* wait until we have a new pic */ + { + boost::unique_lock lock(is->pictq_mutex); + while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && + !is->quit) { + is->pictq_cond.timed_wait(lock, boost::posix_time::milliseconds(1)); + } + } + + if(is->quit) + return -1; + + // windex is set to 0 initially + vp = &is->pictq[is->pictq_windex]; + + // Convert the image into YUV format that SDL uses + if(is->sws_context == NULL) { + int w = is->video_st->codec->width; + int h = is->video_st->codec->height; + is->sws_context = sws_getContext(w, h, + is->video_st->codec->pix_fmt, w, h, + PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); + if(is->sws_context == NULL) + throw std::runtime_error("Cannot initialize the conversion context!\n"); + } + + vp->data =(uint8_t*) malloc(is->video_st->codec->width * is->video_st->codec->height * 4); + + sws_scale(is->sws_context, pFrame->data, pFrame->linesize, + 0, is->video_st->codec->height, &vp->data, is->rgbaFrame->linesize); + + + vp->pts = pts; + + // now we inform our display thread that we have a pic ready + if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) { + is->pictq_windex = 0; + } + is->pictq_mutex.lock(); + is->pictq_size++; + is->pictq_mutex.unlock(); return 0; } - int AVPacketQueue::get(AVPacket* pkt, int block) - { - AVPacketList* pkt1; + double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) { - while (true) - { - pkt1 = mFirstPacket; - if (pkt1 != NULL) - { - mFirstPacket = pkt1->next; + double frame_delay; - if (mFirstPacket == NULL) mLastPacket = NULL; - - mNumPackets--; - mSize -= pkt1->pkt.size; - *pkt = pkt1->pkt; - av_free(pkt1); - return 1; - } - else if (block == 0) - { - return 0; - } - else - { - return -1; - } + if(pts != 0) { + /* if we have pts, set video clock to it */ + is->video_clock = pts; + } else { + /* if we aren't given a pts, set it to the clock */ + pts = is->video_clock; } + /* update the video clock */ + frame_delay = av_q2d(is->video_st->codec->time_base); + /* if we are repeating a frame, adjust clock accordingly */ + frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); + is->video_clock += frame_delay; + return pts; } - //------------------------------------------------------------------------------------------- + uint64_t global_video_pkt_pts = AV_NOPTS_VALUE; - VideoPlayer::VideoPlayer(Ogre::SceneManager *sceneMgr) - : mAvContext(NULL) - , mVideoStreamId(-1) - , mAudioStreamId(-1) - , mVideoClock(0) - , mAudioClock(0) - , mClock(0) + /* These are called whenever we allocate a frame + * buffer. We use this to store the global_pts in + * a frame at the time it is allocated. + */ + int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) { + int ret = avcodec_default_get_buffer(c, pic); + uint64_t *pts = (uint64_t*)av_malloc(sizeof(uint64_t)); + *pts = global_video_pkt_pts; + pic->opaque = pts; + return ret; + } + void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) { + if(pic) av_freep(&pic->opaque); + avcodec_default_release_buffer(c, pic); + } + + int video_thread(void *arg) { + VideoState *is = (VideoState *)arg; + AVPacket pkt1, *packet = &pkt1; + int len1, frameFinished; + AVFrame *pFrame; + double pts; + + pFrame = avcodec_alloc_frame(); + + is->rgbaFrame = avcodec_alloc_frame(); + avpicture_alloc ((AVPicture *)is->rgbaFrame, PIX_FMT_RGBA, is->video_st->codec->width, is->video_st->codec->height); + + + for(;;) { + if(packet_queue_get(&is->videoq, packet, 1) < 0) { + // means we quit getting packets + break; + } + pts = 0; + + // Save global pts to be stored in pFrame + global_video_pkt_pts = packet->pts; + // Decode video frame + len1 = avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, + packet); + if(packet->dts == AV_NOPTS_VALUE + && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) { + pts = *(uint64_t *)pFrame->opaque; + } else if(packet->dts != AV_NOPTS_VALUE) { + pts = packet->dts; + } else { + pts = 0; + } + pts *= av_q2d(is->video_st->time_base); + + + // Did we get a video frame? + if(frameFinished) { + pts = synchronize_video(is, pFrame, pts); + if(queue_picture(is, pFrame, pts) < 0) { + break; + } + } + av_free_packet(packet); + } + + SDL_CloseAudio(); + + av_free(pFrame); + + avpicture_free((AVPicture *)is->rgbaFrame); + av_free(is->rgbaFrame); + + return 0; + } + + int stream_component_open(VideoState *is, int stream_index, AVFormatContext *pFormatCtx) { - Ogre::MaterialPtr videoMaterial = Ogre::MaterialManager::getSingleton ().create("VideoMaterial", "General"); - videoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - videoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - videoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); - mTextureUnit = videoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(); + AVCodecContext *codecCtx; + AVCodec *codec; + SDL_AudioSpec wanted_spec, spec; + + if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) { + return -1; + } + + // Get a pointer to the codec context for the video stream + codecCtx = pFormatCtx->streams[stream_index]->codec; + + if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) { + // Set audio settings from codec info + wanted_spec.freq = codecCtx->sample_rate; + wanted_spec.format = AUDIO_S16SYS; + wanted_spec.channels = codecCtx->channels; + wanted_spec.silence = 0; + wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; + wanted_spec.callback = audio_callback; + wanted_spec.userdata = is; + + if(SDL_OpenAudio(&wanted_spec, &spec) < 0) { + fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); + return -1; + } + is->audio_hw_buf_size = spec.size; + } + codec = avcodec_find_decoder(codecCtx->codec_id); + if(!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)) { + fprintf(stderr, "Unsupported codec!\n"); + return -1; + } + + switch(codecCtx->codec_type) { + case AVMEDIA_TYPE_AUDIO: + is->audioStream = stream_index; + is->audio_st = pFormatCtx->streams[stream_index]; + is->audio_buf_size = 0; + is->audio_buf_index = 0; + + /* averaging filter for audio sync */ + is->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); + is->audio_diff_avg_count = 0; + /* Correct audio only if larger error than this */ + is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / codecCtx->sample_rate; + + memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); + packet_queue_init(&is->audioq); + SDL_PauseAudio(0); + break; + case AVMEDIA_TYPE_VIDEO: + is->videoStream = stream_index; + is->video_st = pFormatCtx->streams[stream_index]; + + is->frame_timer = (double)av_gettime() / 1000000.0; + is->frame_last_delay = 40e-3; + is->video_current_pts_time = av_gettime(); + + packet_queue_init(&is->videoq); + is->video_thread = boost::thread(video_thread, is); + codecCtx->get_buffer = our_get_buffer; + codecCtx->release_buffer = our_release_buffer; + + break; + default: + break; + } + + + } + + int decode_interrupt_cb(void) { + return (global_video_state && global_video_state->quit); + } + + int decode_thread(void *arg) { + + VideoState *is = (VideoState *)arg; + AVFormatContext *pFormatCtx = avformat_alloc_context (); + AVPacket pkt1, *packet = &pkt1; + + int video_index = -1; + int audio_index = -1; + int i; + + is->videoStream=-1; + is->audioStream=-1; + is->quit = 0; + + Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton ().openResource (is->resourceName); + if(stream.isNull ()) + throw std::runtime_error("Failed to open video resource"); + + AVIOContext *ioContext = 0; + + ioContext = avio_alloc_context(NULL, 0, 0, &stream, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if (!ioContext) + throw std::runtime_error("Failed to allocate ioContext "); + + pFormatCtx->pb = ioContext; + + global_video_state = is; + // will interrupt blocking functions if we quit! + //url_set_interrupt_cb(decode_interrupt_cb); + + // Open video file + /// \todo leak here, ffmpeg or valgrind bug ? + if (avformat_open_input(&pFormatCtx, is->resourceName.c_str(), NULL, NULL)) + throw std::runtime_error("Failed to open video input"); + + // Retrieve stream information + if(avformat_find_stream_info(pFormatCtx, NULL)<0) + throw std::runtime_error("Failed to retrieve stream information"); + + // Dump information about file onto standard error + av_dump_format(pFormatCtx, 0, is->resourceName.c_str(), 0); + + for(i=0; inb_streams; i++) { + if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && + video_index < 0) { + video_index=i; + } + if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && + audio_index < 0) { + audio_index=i; + } + } + + if(audio_index >= 0) { + stream_component_open(is, audio_index, pFormatCtx); + } + if(video_index >= 0) { + stream_component_open(is, video_index, pFormatCtx); + } + + if(is->videoStream >= 0 /*|| is->audioStream < 0*/) + { + + // main decode loop + + for(;;) { + if(is->quit) { + break; + } + if( (is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || + is->videoq.size > MAX_VIDEOQ_SIZE) { + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + continue; + } + if(av_read_frame(pFormatCtx, packet) < 0) { + break; + } + // Is this a packet from the video stream? + if(packet->stream_index == is->videoStream) { + packet_queue_put(&is->videoq, packet); + } else if(packet->stream_index == is->audioStream) { + packet_queue_put(&is->audioq, packet); + } else { + av_free_packet(packet); + } + } + /* all done - wait for it */ + while(!is->quit) { + // EOF reached, all packets processed, we can exit now + if (is->audioq.nb_packets == 0 && is->videoq.nb_packets == 0) + break; + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + } + + is->quit = 1; + + is->audioq.cond.notify_one (); + is->videoq.cond.notify_one (); + + is->video_thread.join(); + + if (is->audioStream >= 0) + avcodec_close(is->audio_st->codec); + if (is->videoStream >= 0) + avcodec_close(is->video_st->codec); + + sws_freeContext (is->sws_context); + + av_close_input_file(pFormatCtx); + pFormatCtx = NULL; + + av_free(ioContext); + + return 0; + } + + + VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) + : mState(NULL) + , mSceneMgr(sceneMgr) + { + mVideoMaterial = Ogre::MaterialManager::getSingleton ().create("VideoMaterial", "General"); + mVideoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(); mRectangle = new Ogre::Rectangle2D(true); mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); @@ -164,357 +799,71 @@ namespace MWRender mRectangle->setVisibilityFlags (0x1); } - VideoPlayer::~VideoPlayer() + VideoPlayer::~VideoPlayer () { - if (mAvContext) - deleteContext(); - - delete mRectangle; + if (mState) + close(); } - void VideoPlayer::play (const std::string& resourceName) + void VideoPlayer::playVideo (const std::string &resourceName) { - mStream = Ogre::ResourceGroupManager::getSingleton ().openResource (resourceName); - - - mVideoStreamId = -1; - mAudioStreamId = -1; - mAudioStream = NULL; - mVideoStream = NULL; - mVideoClock = 0; - mAudioClock = 0; - mClock = 0; - - // if something is already playing, close it - if (mAvContext) + if (mState) close(); mRectangle->setVisible(true); MWBase::Environment::get().getWindowManager ()->pushGuiMode (MWGui::GM_Video); + mState = new VideoState; - // BASIC INITIALIZATION - - // Load all the decoders + // Register all formats and codecs av_register_all(); - AVIOContext *ioContext = 0; - - int err = 0; - - mAvContext = avformat_alloc_context(); - if (!mAvContext) - throwError(0); - - ioContext = avio_alloc_context(NULL, 0, 0, &mStream, OgreResource_Read, OgreResource_Write, OgreResource_Seek); - if (!ioContext) - throwError(0); - - mAvContext->pb = ioContext; - - err = avformat_open_input(&mAvContext, resourceName.c_str(), NULL, NULL); - if (err != 0) - throwError(err); - - err = avformat_find_stream_info(mAvContext, 0); - if (err < 0) - throwError(err); - - - - - // Find the video stream among the different streams - for (unsigned int i = 0; i < mAvContext->nb_streams; i++) - { - if (mAvContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) - { - mVideoStreamId = i; - mVideoStream = mAvContext->streams[i]; - break; - } + if(SDL_Init(SDL_INIT_AUDIO)) { + throw std::runtime_error("Failed to initialize SDL"); } - if (mVideoStreamId < 0) - throw std::runtime_error("No video stream found in the video"); + mState->refresh = 0; + mState->resourceName = resourceName; - // Get the video decoder - mVideoCodec = avcodec_find_decoder(mVideoStream->codec->codec_id); - if (NULL == mVideoCodec) - throw std::runtime_error("No video decoder found"); + schedule_refresh(mState, 40); - // Load the video codec - err = avcodec_open2(mVideoStream->codec, mVideoCodec, 0); - if (err < 0) - throwError (err); - - - - // Find the audio stream among the different streams - for (unsigned int i = 0; i < mAvContext->nb_streams; i++) - { - if (mAvContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) - { - mAudioStreamId = i; - mAudioStream = mAvContext->streams[i]; - break; - } - } - - if (mAudioStreamId >= 0) - { - // Get the audio decoder - mAudioCodec = avcodec_find_decoder(mAudioStream->codec->codec_id); - if (mAudioCodec == NULL) - { - throw std::runtime_error("Stream doesn't have an audio codec"); - } - - // Load the audio codec - err = avcodec_open2(mAudioStream->codec, mAudioCodec, 0); - if (err < 0) - throwError (err); - } - - - - // Create the frame buffers - mRawFrame = avcodec_alloc_frame(); - mRGBAFrame = avcodec_alloc_frame(); - if (!mRawFrame || !mRGBAFrame) - { - throw std::runtime_error("Can't allocate video frames"); - } - - - avpicture_alloc ((AVPicture *)mRGBAFrame, PIX_FMT_RGBA, mVideoStream->codec->width, mVideoStream->codec->height); - - - // Setup the image scaler - // All this does is convert from YUV to RGB - note it would be faster to do this in a shader, - // but i'm not worried about performance just yet - mSwsContext = sws_getContext(mVideoStream->codec->width, mVideoStream->codec->height, - mVideoStream->codec->pix_fmt, - mVideoStream->codec->width, mVideoStream->codec->height, - PIX_FMT_RGBA, - SWS_BICUBIC, NULL, NULL, NULL); - if (!mSwsContext) - throw std::runtime_error("Can't create SWS Context"); - - mTextureUnit->setTextureName (""); - - if (!Ogre::TextureManager::getSingleton ().getByName("VideoTexture").isNull()) - Ogre::TextureManager::getSingleton().remove("VideoTexture"); - - mVideoTexture = Ogre::TextureManager::getSingleton().createManual( - "VideoTexture", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - mVideoStream->codec->width, mVideoStream->codec->height, - 0, - Ogre::PF_BYTE_RGBA, - Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); - - // initialize to (0, 0, 0, 1) - std::vector buffer; - buffer.resize(mVideoStream->codec->width * mVideoStream->codec->height); - for (int p=0; pcodec->width * mVideoStream->codec->height; ++p) - { - buffer[p] = (255 << 24); - } - memcpy(mVideoTexture->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mVideoStream->codec->width*mVideoStream->codec->height*4); - mVideoTexture->getBuffer()->unlock(); - - mTextureUnit->setTextureName ("VideoTexture"); - - - // Queue up some packets - while( - mVideoPacketQueue.getNumPackets()av_sync_type = DEFAULT_AV_SYNC_TYPE; + mState->parse_thread = boost::thread(decode_thread, mState); } - void VideoPlayer::throwError(int error) + void VideoPlayer::update () { - char buffer[4096] = {0}; - - if (0 == av_strerror(error, buffer, sizeof(buffer))) + if (mState && mState->refresh) { - std::stringstream msg; - msg << "FFMPEG error: "; - msg << buffer << std::endl; - throw std::runtime_error(msg.str()); + video_refresh_timer (mState); + mState->refresh--; } - else - throw std::runtime_error("Unknown FFMPEG error"); - } - - void VideoPlayer::update() - { - if (!mAvContext) - return; - - double dt = mTimer.getMilliseconds () / 1000.f; - mTimer.reset (); - - //UpdateAudio(fTime); - //std::cout << "num packets: " << mVideoPacketQueue.getNumPackets() << " clocks: " << mVideoClock << " , " << mClock << std::endl; - while (!mVideoPacketQueue.isEmpty() && mVideoClock < mClock) + if (mState && mState->quit) { - while( - mVideoPacketQueue.getNumPackets()getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("VideoTexture"); } - void VideoPlayer::decodeNextVideoFrame () + void VideoPlayer::close() { - // Make sure there is something to decode - assert (mVideoPacketQueue.getNumPackets ()); + mState->quit = 1; - // Get the front frame and decode it - AVPacket packet; - mVideoPacketQueue.get(&packet, 1); + mState->parse_thread.join (); - int res; - int didDecodeFrame = 0; - res = avcodec_decode_video2(mVideoStream->codec, mRawFrame, &didDecodeFrame, &packet); + delete mState; + mState = NULL; - if (res < 0 || !didDecodeFrame) - throw std::runtime_error ("an error occured while decoding the video frame"); - - // Set video clock to the PTS of this packet (presentation timestamp) - double pts = 0; - if (packet.pts != -1.0) pts = packet.pts; - pts *= av_q2d(mVideoStream->time_base); - mVideoClock = pts; - - // Convert the frame to RGB - sws_scale(mSwsContext, - mRawFrame->data, mRawFrame->linesize, - 0, mVideoStream->codec->height, - mRGBAFrame->data, mRGBAFrame->linesize); - - - Ogre::HardwarePixelBufferSharedPtr pixelBuffer = mVideoTexture->getBuffer(); - Ogre::PixelBox pb(mVideoStream->codec->width, mVideoStream->codec->height, 1, Ogre::PF_BYTE_RGBA, mRGBAFrame->data[0]); - pixelBuffer->blitFromMemory(pb); - - if (packet.data != NULL) av_free_packet(&packet); - } - - void VideoPlayer::close () - { mRectangle->setVisible (false); MWBase::Environment::get().getWindowManager ()->removeGuiMode (MWGui::GM_Video); - deleteContext(); } - void VideoPlayer::deleteContext() + bool VideoPlayer::isPlaying () { - while (mVideoPacketQueue.getNumPackets ()) - { - AVPacket packet; - mVideoPacketQueue.get(&packet, 1); - if (packet.data != NULL) av_free_packet(&packet); - } - while (mAudioPacketQueue.getNumPackets ()) - { - AVPacket packet; - mAudioPacketQueue.get(&packet, 1); - if (packet.data != NULL) av_free_packet(&packet); - } - - if (mVideoStream && mVideoStream->codec != NULL) avcodec_close(mVideoStream->codec); - if (mAudioStream && mAudioStream->codec != NULL) avcodec_close(mAudioStream->codec); - - avpicture_free((AVPicture *)mRGBAFrame); - - if (mRawFrame) - av_free(mRawFrame); - if (mRGBAFrame) - av_free(mRGBAFrame); - - sws_freeContext(mSwsContext); - - avformat_close_input(&mAvContext); - - mAvContext = NULL; + return mState != NULL; } - - - bool VideoPlayer::addToBuffer() - { - if(mAvContext) - { - AVPacket packet; - if (av_read_frame(mAvContext, &packet) >= 0) - { - if (packet.stream_index == mVideoStreamId) - { - // I don't believe this is necessary. - /* - if(mClock==0) - { - mClock = packet.dts; - mClock *= av_q2d(mVideoStream->time_base); - std::cout << "Initializing clock to: " << mClock << std::endl; - } - */ - - mVideoPacketQueue.put(&packet); - - return true; - } - else if (packet.stream_index == mAudioStreamId && mAudioStream) - { - mAudioPacketQueue.put(&packet); - return true; - } - else - { - av_free_packet(&packet); - return false; - } - } - } - - return false; - } } - -//#endif diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 466bb7902..9766ba8ee 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -1,137 +1,162 @@ -#ifndef MWRENDER_VIDEOPLAYER_H -#define MWRENDER_VIDEOPLAYER_H +#ifndef VIDEOPLAYER_H +#define VIDEOPLAYER_H -//#ifdef OPENMW_USE_FFMPEG +#include +#include + +#include - -#include - -#include -#include -#include - -namespace Ogre +#define __STDC_CONSTANT_MACROS +#include +extern "C" { - class Rectangle2D; - class SceneManager; - class TextureUnitState; +#include +#include +#include } -struct AVFormatContext; -struct AVCodecContext; -struct AVCodec; -struct AVStream; -struct AVFrame; -struct SwsContext; -struct AVPacket; -struct AVPacketList; +#include +#include + +#include +#include + +#define SDL_AUDIO_BUFFER_SIZE 1024 +#define MAX_AUDIOQ_SIZE (5 * 16 * 1024) +#define MAX_VIDEOQ_SIZE (5 * 256 * 1024) +#define AV_SYNC_THRESHOLD 0.01 +#define AV_NOSYNC_THRESHOLD 10.0 +#define SAMPLE_CORRECTION_PERCENT_MAX 10 +#define AUDIO_DIFF_AVG_NB 20 +#define VIDEO_PICTURE_QUEUE_SIZE 1 +#define DEFAULT_AV_SYNC_TYPE AV_SYNC_VIDEO_MASTER + + namespace MWRender { - /// A simple queue used to queue raw audio and video data. - class AVPacketQueue - { - public: - AVPacketQueue(); - int put(AVPacket* pkt); - int get(AVPacket* pkt, int block); - bool isEmpty() const { return mNumPackets == 0; } - int getNumPackets() const { return mNumPackets; } - int getSize() const { return mSize; } + struct PacketQueue { + PacketQueue () : + first_pkt(NULL), last_pkt(NULL), nb_packets(0), size(0) + {} + AVPacketList *first_pkt, *last_pkt; + int nb_packets; + int size; - private: - AVPacketList* mFirstPacket; - AVPacketList* mLastPacket; - int mNumPackets; - int mSize; + boost::mutex mutex; + boost::condition_variable cond; + }; + struct VideoPicture { + VideoPicture () : + data(NULL), pts(0) + {} + uint8_t* data; + + double pts; + }; + + static void packet_queue_flush(PacketQueue *q); + + struct VideoState { + VideoState () : + videoStream(-1), audioStream(-1), av_sync_type(0), external_clock(0), + external_clock_time(0), audio_clock(0), audio_st(NULL), audio_buf_size(0), + audio_pkt_data(NULL), audio_pkt_size(0), audio_hw_buf_size(0), audio_diff_cum(0), audio_diff_avg_coef(0), + audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), frame_last_delay(0), + video_clock(0), video_current_pts(0), video_current_pts_time(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), + pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), sws_context(NULL) + {} + + + ~VideoState() + { + packet_queue_flush (&audioq); + packet_queue_flush (&videoq); + + if (pictq_size >= 1) + free (pictq[0].data); + } + + int videoStream, audioStream; + + int av_sync_type; + double external_clock; /* external clock base */ + int64_t external_clock_time; + double audio_clock; + AVStream *audio_st; + PacketQueue audioq; + DECLARE_ALIGNED(16, uint8_t, audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]); + unsigned int audio_buf_size; + unsigned int audio_buf_index; + AVPacket audio_pkt; + uint8_t *audio_pkt_data; + int audio_pkt_size; + int audio_hw_buf_size; + double audio_diff_cum; /* used for AV difference average computation */ + double audio_diff_avg_coef; + double audio_diff_threshold; + int audio_diff_avg_count; + double frame_timer; + double frame_last_pts; + double frame_last_delay; + double video_clock; ///. This is done for portability +# reasons because not all systems place things in SDL/ (see FreeBSD). + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +FIND_PATH(SDL_INCLUDE_DIR SDL.h + HINTS + $ENV{SDLDIR} + PATH_SUFFIXES include/SDL include + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include/SDL12 + /usr/local/include/SDL11 # FreeBSD ports + /usr/include/SDL12 + /usr/include/SDL11 + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) +#MESSAGE("SDL_INCLUDE_DIR is ${SDL_INCLUDE_DIR}") + +# SDL-1.1 is the name used by FreeBSD ports... +# don't confuse it for the version number. +FIND_LIBRARY(SDL_LIBRARY_TEMP + NAMES SDL SDL-1.1 + HINTS + $ENV{SDLDIR} + PATH_SUFFIXES lib64 lib + PATHS + /sw + /opt/local + /opt/csw + /opt +) + +#MESSAGE("SDL_LIBRARY_TEMP is ${SDL_LIBRARY_TEMP}") + +IF(NOT SDL_BUILDING_LIBRARY) + IF(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDLmain for compatibility even though they don't + # necessarily need it. + FIND_LIBRARY(SDLMAIN_LIBRARY + NAMES SDLmain SDLmain-1.1 + HINTS + $ENV{SDLDIR} + PATH_SUFFIXES lib64 lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) + ENDIF(NOT ${SDL_INCLUDE_DIR} MATCHES ".framework") +ENDIF(NOT SDL_BUILDING_LIBRARY) + +# SDL may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDLmain -lSDL -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +SET(SDL_FOUND "NO") +IF(SDL_LIBRARY_TEMP) + # For SDLmain + IF(NOT SDL_BUILDING_LIBRARY) + IF(SDLMAIN_LIBRARY) + SET(SDL_LIBRARY_TEMP ${SDLMAIN_LIBRARY} ${SDL_LIBRARY_TEMP}) + ENDIF(SDLMAIN_LIBRARY) + ENDIF(NOT SDL_BUILDING_LIBRARY) + + # For OS X, SDL uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + IF(APPLE) + SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} "-framework Cocoa") + ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + IF(NOT APPLE) + SET(SDL_LIBRARY_TEMP ${SDL_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(NOT APPLE) + + # For MinGW library + IF(MINGW) + SET(SDL_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL_LIBRARY_TEMP}) + ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL_LIBRARY ${SDL_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL_LIBRARY_TEMP "${SDL_LIBRARY_TEMP}" CACHE INTERNAL "") + + SET(SDL_FOUND "YES") +ENDIF(SDL_LIBRARY_TEMP) + +#MESSAGE("SDL_LIBRARY is ${SDL_LIBRARY}") + From 0ce5ade6d816cb4eaf9867bfb596e316d8a9806a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 11 Dec 2012 23:06:06 +0100 Subject: [PATCH 064/916] DataStreamPtr fix, indentation fixes --- apps/openmw/mwrender/videoplayer.cpp | 112 ++++++++++++++------------- apps/openmw/mwrender/videoplayer.hpp | 2 + 2 files changed, 59 insertions(+), 55 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 3ddc7961c..40d1a7188 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -11,49 +11,49 @@ namespace MWRender int OgreResource_Read(void *opaque, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + Ogre::DataStreamPtr stream = static_cast(opaque)->stream; - int num_read = stream->size() - stream->tell(); + int num_read = stream->size() - stream->tell(); - if (num_read > buf_size) - num_read = buf_size; + if (num_read > buf_size) + num_read = buf_size; - stream->read(buf, num_read); - return num_read; + stream->read(buf, num_read); + return num_read; } int OgreResource_Write(void *opaque, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + Ogre::DataStreamPtr stream = static_cast(opaque)->stream; - int num_write = stream->size() - stream->tell(); + int num_write = stream->size() - stream->tell(); - if (num_write > buf_size) - num_write = buf_size; + if (num_write > buf_size) + num_write = buf_size; - stream->write (buf, num_write); - return num_write; + stream->write (buf, num_write); + return num_write; } int64_t OgreResource_Seek(void *opaque, int64_t offset, int whence) { - Ogre::DataStreamPtr stream = *((Ogre::DataStreamPtr*)opaque); + Ogre::DataStreamPtr stream = static_cast(opaque)->stream; - switch (whence) - { + switch (whence) + { case SEEK_SET: - stream->seek(offset); + stream->seek(offset); case SEEK_CUR: - stream->seek(stream->tell() + offset); + stream->seek(stream->tell() + offset); case SEEK_END: - stream->seek(stream->size() + offset); + stream->seek(stream->size() + offset); case AVSEEK_SIZE: - return stream->size(); + return stream->size(); default: - return -1; - } + return -1; + } - return stream->tell(); + return stream->tell(); } @@ -107,7 +107,7 @@ namespace MWRender if (pkt1) { q->first_pkt = pkt1->next; if (!q->first_pkt) - q->last_pkt = NULL; + q->last_pkt = NULL; q->nb_packets--; q->size -= pkt1->pkt.size; *pkt = pkt1->pkt; @@ -247,21 +247,21 @@ namespace MWRender if(len1 < 0) { - /* if error, skip frame */ - is->audio_pkt_size = 0; - break; + /* if error, skip frame */ + is->audio_pkt_size = 0; + break; } is->audio_pkt_data += len1; is->audio_pkt_size -= len1; if(data_size <= 0) { /* No data yet, get more frames */ - continue; + continue; } pts = is->audio_clock; *pts_ptr = pts; n = 2 * is->audio_st->codec->channels; is->audio_clock += (double)data_size / - (double)(n * is->audio_st->codec->sample_rate); + (double)(n * is->audio_st->codec->sample_rate); /* We have data, return it and come back for more later */ return data_size; @@ -295,13 +295,13 @@ namespace MWRender /* We have already sent all our data; get more */ audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts); if(audio_size < 0) { - /* If error, output silence */ - is->audio_buf_size = 1024; - memset(is->audio_buf, 0, is->audio_buf_size); + /* If error, output silence */ + is->audio_buf_size = 1024; + memset(is->audio_buf, 0, is->audio_buf_size); } else { - audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, - audio_size, pts); - is->audio_buf_size = audio_size; + audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, + audio_size, pts); + is->audio_buf_size = audio_size; } is->audio_buf_index = 0; } @@ -387,8 +387,8 @@ namespace MWRender delay = vp->pts - is->frame_last_pts; /* the pts from last time */ if(delay <= 0 || delay >= 1.0) { - /* if incorrect delay, use previous one */ - delay = is->frame_last_delay; + /* if incorrect delay, use previous one */ + delay = is->frame_last_delay; } /* save for next time */ is->frame_last_delay = delay; @@ -396,27 +396,27 @@ namespace MWRender /* update delay to sync to audio if not master source */ if(is->av_sync_type != AV_SYNC_VIDEO_MASTER) { - ref_clock = get_master_clock(is); - diff = vp->pts - ref_clock; + ref_clock = get_master_clock(is); + diff = vp->pts - ref_clock; - /* Skip or repeat the frame. Take delay into account - FFPlay still doesn't "know if this is the best guess." */ - sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; - if(fabs(diff) < AV_NOSYNC_THRESHOLD) { - if(diff <= -sync_threshold) { - delay = 0; - } else if(diff >= sync_threshold) { - delay = 2 * delay; - } - } + /* Skip or repeat the frame. Take delay into account + FFPlay still doesn't "know if this is the best guess." */ + sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; + if(fabs(diff) < AV_NOSYNC_THRESHOLD) { + if(diff <= -sync_threshold) { + delay = 0; + } else if(diff >= sync_threshold) { + delay = 2 * delay; + } + } } is->frame_timer += delay; /* computer the REAL delay */ actual_delay = is->frame_timer - (av_gettime() / 1000000.0); if(actual_delay < 0.010) { - /* Really it should skip the picture instead */ - actual_delay = 0.010; + /* Really it should skip the picture instead */ + actual_delay = 0.010; } schedule_refresh(is, (int)(actual_delay * 1000 + 0.5)); @@ -425,14 +425,15 @@ namespace MWRender /* update queue for next picture! */ if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) { - is->pictq_rindex = 0; + is->pictq_rindex = 0; } is->pictq_mutex.lock(); is->pictq_size--; is->pictq_cond.notify_one (); is->pictq_mutex.unlock (); } - } else { + } + else { schedule_refresh(is, 100); } } @@ -563,7 +564,7 @@ namespace MWRender if(frameFinished) { pts = synchronize_video(is, pFrame, pts); if(queue_picture(is, pFrame, pts) < 0) { - break; + break; } } av_free_packet(packet); @@ -673,10 +674,11 @@ namespace MWRender Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton ().openResource (is->resourceName); if(stream.isNull ()) throw std::runtime_error("Failed to open video resource"); + is->stream = stream; AVIOContext *ioContext = 0; - ioContext = avio_alloc_context(NULL, 0, 0, &stream, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + ioContext = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); if (!ioContext) throw std::runtime_error("Failed to allocate ioContext "); @@ -845,7 +847,7 @@ namespace MWRender } if (!Ogre::TextureManager::getSingleton ().getByName ("VideoTexture").isNull ()) - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("VideoTexture"); + mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("VideoTexture"); } void VideoPlayer::close() diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 9766ba8ee..67a22a506 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -108,6 +108,8 @@ namespace MWRender AVStream *video_st; PacketQueue videoq; + Ogre::DataStreamPtr stream; + SwsContext* sws_context; VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; From faad64b2545608a8781800ebfcf3ab265411c944 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 12 Dec 2012 01:13:53 +0100 Subject: [PATCH 065/916] Esc cancels the video --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 1 + 6 files changed, 15 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 526f865bc..198a20d45 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -306,6 +306,7 @@ namespace MWBase /// \todo this does not belong here virtual void playVideo(const std::string& name) = 0; + virtual void stopVideo() = 0; }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6a1c3aa9b..f7cc0f88e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -508,6 +508,8 @@ namespace MWInput { if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) mWindows.popGuiMode(); + else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) + MWBase::Environment::get().getWorld ()->stopVideo (); else mWindows.pushGuiMode (MWGui::GM_MainMenu); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5663ded09..811d000a9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -931,4 +931,9 @@ void RenderingManager::playVideo(const std::string& name) mVideoPlayer->playVideo ("video/" + name); } +void RenderingManager::stopVideo() +{ + mVideoPlayer->close (); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index ee64a371e..02b4bcef6 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -197,6 +197,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setupExternalRendering (MWRender::ExternalRendering& rendering); void playVideo(const std::string& name); + void stopVideo(); protected: virtual void windowResized(Ogre::RenderWindow* rw); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2257b8a07..8eb121d37 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1291,4 +1291,9 @@ namespace MWWorld { mRendering->playVideo(name); } + + void World::stopVideo () + { + mRendering->stopVideo(); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 349fd163c..1c1352913 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -335,6 +335,7 @@ namespace MWWorld /// \todo this does not belong here virtual void playVideo(const std::string& name); + virtual void stopVideo(); }; } From fe384a1600b1bf057faff7d7d4f1fa5a1bc58ae1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 12 Dec 2012 01:30:34 +0100 Subject: [PATCH 066/916] pause 3d rendering while the video plays --- apps/openmw/mwrender/videoplayer.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 40d1a7188..46fa4b9e9 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -816,6 +816,17 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->pushGuiMode (MWGui::GM_Video); + // Turn off rendering except the GUI + mSceneMgr->clearSpecialCaseRenderQueues(); + // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work. + for (int i = 0; i < Ogre::RENDER_QUEUE_MAX; ++i) + { + if (i > 0 && i < 96) + mSceneMgr->addSpecialCaseRenderQueue(i); + } + mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + + mState = new VideoState; // Register all formats and codecs @@ -861,6 +872,9 @@ namespace MWRender mRectangle->setVisible (false); MWBase::Environment::get().getWindowManager ()->removeGuiMode (MWGui::GM_Video); + + mSceneMgr->clearSpecialCaseRenderQueues(); + mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); } bool VideoPlayer::isPlaying () From 9e2d4f8b7cc4751552c8f4d9a31dbf7ed04c083c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Dec 2012 19:32:10 -0800 Subject: [PATCH 067/916] Avoid potential NULL dereference --- apps/openmw/mwrender/videoplayer.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 46fa4b9e9..612b37c0a 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -142,16 +142,12 @@ namespace MWRender } double get_audio_clock(VideoState *is) { double pts; - int hw_buf_size, bytes_per_sec, n; pts = is->audio_clock; /* maintained in the audio thread */ - hw_buf_size = is->audio_buf_size - is->audio_buf_index; - bytes_per_sec = 0; - n = is->audio_st->codec->channels * 2; if(is->audio_st) { - bytes_per_sec = is->audio_st->codec->sample_rate * n; - } - if(bytes_per_sec) { + int n = is->audio_st->codec->channels * 2; + int bytes_per_sec = is->audio_st->codec->sample_rate * n; + int hw_buf_size = is->audio_buf_size - is->audio_buf_index; pts -= (double)hw_buf_size / bytes_per_sec; } return pts; From 3519934f273a2ddbe81e284c811cd577cf68e1fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Dec 2012 19:36:04 -0800 Subject: [PATCH 068/916] Add a missing return value --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 612b37c0a..b65458b63 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -646,7 +646,7 @@ namespace MWRender break; } - + return 0; } int decode_interrupt_cb(void) { From 277248cdcbf1caa3673af3ee45957690aec98579 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Dec 2012 19:43:07 -0800 Subject: [PATCH 069/916] Fix some "comparison between signed and unsigned" warnings --- apps/openmw/mwrender/videoplayer.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b65458b63..7e7fcd0d6 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -275,7 +275,7 @@ namespace MWRender is->audio_pkt_data = pkt->data; is->audio_pkt_size = pkt->size; /* if update, update the audio clock w/pts */ - if(pkt->pts != AV_NOPTS_VALUE) { + if(pkt->pts != (int64_t)AV_NOPTS_VALUE) { is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; } } @@ -345,7 +345,8 @@ namespace MWRender if (is->video_st->codec->width != 0 && is->video_st->codec->height != 0) { Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().getByName("VideoTexture"); - if (texture.isNull () || texture->getWidth() != is->video_st->codec->width || texture->getHeight() != is->video_st->codec->height) + if (texture.isNull () || texture->getWidth() != (size_t)is->video_st->codec->width || + texture->getHeight() != (size_t)is->video_st->codec->height) { Ogre::TextureManager::getSingleton ().remove ("VideoTexture"); texture = Ogre::TextureManager::getSingleton().createManual( @@ -545,10 +546,10 @@ namespace MWRender // Decode video frame len1 = avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, packet); - if(packet->dts == AV_NOPTS_VALUE + if(packet->dts == (int64_t)AV_NOPTS_VALUE && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) { pts = *(uint64_t *)pFrame->opaque; - } else if(packet->dts != AV_NOPTS_VALUE) { + } else if(packet->dts != (int64_t)AV_NOPTS_VALUE) { pts = packet->dts; } else { pts = 0; @@ -582,7 +583,7 @@ namespace MWRender AVCodec *codec; SDL_AudioSpec wanted_spec, spec; - if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) { + if(stream_index < 0 || (unsigned int)stream_index >= pFormatCtx->nb_streams) { return -1; } @@ -661,7 +662,7 @@ namespace MWRender int video_index = -1; int audio_index = -1; - int i; + unsigned int i; is->videoStream=-1; is->audioStream=-1; From 2efdafecd9d7c6b5fb0d044cf67cefccb5db461b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Dec 2012 20:11:48 -0800 Subject: [PATCH 070/916] Indentation fixes --- apps/openmw/mwrender/videoplayer.cpp | 98 +++++++++++++--------------- 1 file changed, 46 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 7e7fcd0d6..c09de3acc 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -188,39 +188,39 @@ namespace MWRender diff = get_audio_clock(is) - ref_clock; if(diff < AV_NOSYNC_THRESHOLD) { // accumulate the diffs - is->audio_diff_cum = diff + is->audio_diff_avg_coef - * is->audio_diff_cum; + is->audio_diff_cum = diff + is->audio_diff_avg_coef * + is->audio_diff_cum; if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) { - is->audio_diff_avg_count++; + is->audio_diff_avg_count++; } else { - avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); - if(fabs(avg_diff) >= is->audio_diff_threshold) { - wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); - min_size = samples_size * ((100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100); - max_size = samples_size * ((100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100); - if(wanted_size < min_size) { - wanted_size = min_size; - } else if (wanted_size > max_size) { - wanted_size = max_size; - } - if(wanted_size < samples_size) { - /* remove samples */ - samples_size = wanted_size; - } else if(wanted_size > samples_size) { - uint8_t *samples_end, *q; - int nb; - /* add samples by copying final sample*/ - nb = (samples_size - wanted_size); - samples_end = (uint8_t *)samples + samples_size - n; - q = samples_end + n; - while(nb > 0) { - memcpy(q, samples_end, n); - q += n; - nb -= n; - } - samples_size = wanted_size; - } - } + avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); + if(fabs(avg_diff) >= is->audio_diff_threshold) { + wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); + min_size = samples_size * ((100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100); + max_size = samples_size * ((100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100); + if(wanted_size < min_size) { + wanted_size = min_size; + } else if (wanted_size > max_size) { + wanted_size = max_size; + } + if(wanted_size < samples_size) { + /* remove samples */ + samples_size = wanted_size; + } else if(wanted_size > samples_size) { + uint8_t *samples_end, *q; + int nb; + /* add samples by copying final sample*/ + nb = (samples_size - wanted_size); + samples_end = (uint8_t *)samples + samples_size - n; + q = samples_end + n; + while(nb > 0) { + memcpy(q, samples_end, n); + q += n; + nb -= n; + } + samples_size = wanted_size; + } + } } } else { /* difference is TOO big; reset diff stuff */ @@ -239,7 +239,7 @@ namespace MWRender while(is->audio_pkt_size > 0) { data_size = buf_size; len1 = avcodec_decode_audio3(is->audio_st->codec, - (int16_t *)audio_buf, &data_size, pkt); + (int16_t*)audio_buf, &data_size, pkt); if(len1 < 0) { @@ -250,14 +250,14 @@ namespace MWRender is->audio_pkt_data += len1; is->audio_pkt_size -= len1; if(data_size <= 0) { - /* No data yet, get more frames */ + /* No data yet, get more frames */ continue; } pts = is->audio_clock; *pts_ptr = pts; n = 2 * is->audio_st->codec->channels; is->audio_clock += (double)data_size / - (double)(n * is->audio_st->codec->sample_rate); + (double)(n * is->audio_st->codec->sample_rate); /* We have data, return it and come back for more later */ return data_size; @@ -296,7 +296,7 @@ namespace MWRender memset(is->audio_buf, 0, is->audio_buf_size); } else { audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, - audio_size, pts); + audio_size, pts); is->audio_buf_size = audio_size; } is->audio_buf_index = 0; @@ -397,7 +397,7 @@ namespace MWRender diff = vp->pts - ref_clock; /* Skip or repeat the frame. Take delay into account - FFPlay still doesn't "know if this is the best guess." */ + FFPlay still doesn't "know if this is the best guess." */ sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; if(fabs(diff) < AV_NOSYNC_THRESHOLD) { if(diff <= -sync_threshold) { @@ -442,8 +442,7 @@ namespace MWRender /* wait until we have a new pic */ { boost::unique_lock lock(is->pictq_mutex); - while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && - !is->quit) { + while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->quit) { is->pictq_cond.timed_wait(lock, boost::posix_time::milliseconds(1)); } } @@ -458,9 +457,9 @@ namespace MWRender if(is->sws_context == NULL) { int w = is->video_st->codec->width; int h = is->video_st->codec->height; - is->sws_context = sws_getContext(w, h, - is->video_st->codec->pix_fmt, w, h, - PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); + is->sws_context = sws_getContext(w, h, is->video_st->codec->pix_fmt, + w, h, PIX_FMT_RGBA, SWS_BICUBIC, + NULL, NULL, NULL); if(is->sws_context == NULL) throw std::runtime_error("Cannot initialize the conversion context!\n"); } @@ -468,7 +467,7 @@ namespace MWRender vp->data =(uint8_t*) malloc(is->video_st->codec->width * is->video_st->codec->height * 4); sws_scale(is->sws_context, pFrame->data, pFrame->linesize, - 0, is->video_st->codec->height, &vp->data, is->rgbaFrame->linesize); + 0, is->video_st->codec->height, &vp->data, is->rgbaFrame->linesize); vp->pts = pts; @@ -544,8 +543,7 @@ namespace MWRender // Save global pts to be stored in pFrame global_video_pkt_pts = packet->pts; // Decode video frame - len1 = avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, - packet); + len1 = avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, packet); if(packet->dts == (int64_t)AV_NOPTS_VALUE && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) { pts = *(uint64_t *)pFrame->opaque; @@ -698,12 +696,10 @@ namespace MWRender av_dump_format(pFormatCtx, 0, is->resourceName.c_str(), 0); for(i=0; inb_streams; i++) { - if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && - video_index < 0) { + if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && video_index < 0) { video_index=i; } - if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && - audio_index < 0) { + if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && audio_index < 0) { audio_index=i; } } @@ -717,15 +713,13 @@ namespace MWRender if(is->videoStream >= 0 /*|| is->audioStream < 0*/) { - // main decode loop - for(;;) { if(is->quit) { break; } - if( (is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || - is->videoq.size > MAX_VIDEOQ_SIZE) { + if((is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || + is->videoq.size > MAX_VIDEOQ_SIZE) { boost::this_thread::sleep(boost::posix_time::milliseconds(10)); continue; } From c2e1595445b73dc349b7f05b300ee5ac1b7a9c82 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Dec 2012 21:01:32 -0800 Subject: [PATCH 071/916] Treat paused sounds as still playing --- apps/openmw/mwsound/openal_output.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index e5169d878..1e862d77a 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -254,7 +254,7 @@ bool OpenAL_SoundStream::isPlaying() alGetSourcei(mSource, AL_SOURCE_STATE, &state); throwALerror(); - if(state == AL_PLAYING) + if(state == AL_PLAYING || state == AL_PAUSED) return true; return !mIsFinished; } @@ -393,7 +393,7 @@ bool OpenAL_Sound::isPlaying() alGetSourcei(mSource, AL_SOURCE_STATE, &state); throwALerror(); - return state==AL_PLAYING; + return state==AL_PLAYING || state==AL_PAUSED; } void OpenAL_Sound::update() From a62d5bbfe41f2041900df3cfce46b4b7f20515e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 11 Dec 2012 23:54:41 -0800 Subject: [PATCH 072/916] Sleep using the absolute time, so the thread creation doesn't add to the wait --- apps/openmw/mwrender/videoplayer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index c09de3acc..afdb5e82d 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -321,9 +321,9 @@ namespace MWRender } */ - void timer_callback (int delay, VideoState* is) + void timer_callback (boost::system_time t, VideoState* is) { - boost::this_thread::sleep (boost::posix_time::milliseconds(delay)); + boost::this_thread::sleep (t); is->refresh++; } @@ -332,8 +332,8 @@ namespace MWRender { //SDL_AddTimer(delay, sdl_refresh_timer_cb, is); //is->refresh_queue.push_back (delay); - - boost::thread (boost::bind(&timer_callback, delay, is)); + boost::system_time t = boost::get_system_time() + boost::posix_time::milliseconds(delay); + boost::thread (boost::bind(&timer_callback, t, is)); } void video_display(VideoState *is) From e82c4afd500aa808a81da700d433b577020a837f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2012 00:36:52 -0800 Subject: [PATCH 073/916] close SDL when closing the video, not after the video loop is finished --- apps/openmw/mwrender/videoplayer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index afdb5e82d..8ae51deba 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -565,8 +565,6 @@ namespace MWRender av_free_packet(packet); } - SDL_CloseAudio(); - av_free(pFrame); avpicture_free((AVPicture *)is->rgbaFrame); @@ -861,6 +859,8 @@ namespace MWRender delete mState; mState = NULL; + SDL_CloseAudio(); + mRectangle->setVisible (false); MWBase::Environment::get().getWindowManager ()->removeGuiMode (MWGui::GM_Video); From 973b5faf25405e2e6ac94c5682844b6169e976de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2012 01:32:16 -0800 Subject: [PATCH 074/916] Keep track of all allocated sources --- apps/openmw/mwsound/openal_output.cpp | 12 ++++++------ apps/openmw/mwsound/openal_output.hpp | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 1e862d77a..abd63590f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -504,8 +504,9 @@ void OpenAL_Output::init(const std::string &devname) ALuint src = 0; alGenSources(1, &src); throwALerror(); - mFreeSources.push_back(src); + mSources.push_back(src); } + mFreeSources.insert(mFreeSources.begin(), mSources.begin(), mSources.end()); } catch(std::exception &e) { @@ -521,11 +522,10 @@ void OpenAL_Output::deinit() { mStreamThread->removeAll(); - while(!mFreeSources.empty()) - { - alDeleteSources(1, &mFreeSources.front()); - mFreeSources.pop_front(); - } + mFreeSources.clear(); + if(mSources.size() > 0) + alDeleteSources(mSources.size(), &mSources[0]); + mSources.clear(); mBufferRefs.clear(); mUnusedBuffers.clear(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index fecffa575..4177c6385 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -21,6 +21,9 @@ namespace MWSound ALCdevice *mDevice; ALCcontext *mContext; + typedef std::vector IDVec; + IDVec mSources; + typedef std::deque IDDq; IDDq mFreeSources; IDDq mUnusedBuffers; From 2c1eceb9f093c209240a47be839acb6d086dae07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2012 02:33:12 -0800 Subject: [PATCH 075/916] Add methods to pause and stop all playing sounds (and music) --- apps/openmw/mwbase/soundmanager.hpp | 6 ++++++ apps/openmw/mwrender/videoplayer.cpp | 3 +++ apps/openmw/mwsound/openal_output.cpp | 27 +++++++++++++++++++++++++ apps/openmw/mwsound/openal_output.hpp | 3 +++ apps/openmw/mwsound/sound_output.hpp | 3 +++ apps/openmw/mwsound/soundmanagerimp.cpp | 13 ++++++++++++ apps/openmw/mwsound/soundmanagerimp.hpp | 6 ++++++ 7 files changed, 61 insertions(+) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 92c177ff3..2fa98cfee 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -112,6 +112,12 @@ namespace MWBase virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0; ///< Is the given sound currently playing on the given object? + virtual void pauseAllSounds() = 0; + ///< Pauses all currently playing sounds, including music. + + virtual void resumeAllSounds() = 0; + ///< Resumes all previously paused sounds. + virtual void update(float duration) = 0; virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0; diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 8ae51deba..1334c1bca 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -3,6 +3,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" @@ -821,6 +822,7 @@ namespace MWRender // Register all formats and codecs av_register_all(); + MWBase::Environment::get().getSoundManager()->pauseAllSounds(); if(SDL_Init(SDL_INIT_AUDIO)) { throw std::runtime_error("Failed to initialize SDL"); } @@ -860,6 +862,7 @@ namespace MWRender mState = NULL; SDL_CloseAudio(); + MWBase::Environment::get().getSoundManager()->resumeAllSounds(); mRectangle->setVisible (false); MWBase::Environment::get().getWindowManager ()->removeGuiMode (MWGui::GM_Video); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index abd63590f..bc6102beb 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -814,6 +814,33 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 } +void OpenAL_Output::pauseAllSounds() +{ + IDVec sources = mSources; + IDDq::const_iterator iter = mFreeSources.begin(); + while(iter != mFreeSources.end()) + { + sources.erase(std::find(sources.begin(), sources.end(), *iter)); + iter++; + } + if(sources.size() > 0) + alSourcePausev(sources.size(), &sources[0]); +} + +void OpenAL_Output::resumeAllSounds() +{ + IDVec sources = mSources; + IDDq::const_iterator iter = mFreeSources.begin(); + while(iter != mFreeSources.end()) + { + sources.erase(std::find(sources.begin(), sources.end(), *iter)); + iter++; + } + if(sources.size() > 0) + alSourcePlayv(sources.size(), &sources[0]); +} + + OpenAL_Output::OpenAL_Output(SoundManager &mgr) : Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0), mLastEnvironment(Env_Normal), mStreamThread(new StreamThread) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 4177c6385..867150741 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -52,6 +52,9 @@ namespace MWSound virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); + virtual void pauseAllSounds(); + virtual void resumeAllSounds(); + OpenAL_Output& operator=(const OpenAL_Output &rhs); OpenAL_Output(const OpenAL_Output &rhs); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 2680ec1db..1cc45559b 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -31,6 +31,9 @@ namespace MWSound virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; + virtual void pauseAllSounds() = 0; + virtual void resumeAllSounds() = 0; + Sound_Output& operator=(const Sound_Output &rhs); Sound_Output(const Sound_Output &rhs); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 8c4798c9d..1414dbb76 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -404,6 +404,19 @@ namespace MWSound } + void SoundManager::pauseAllSounds() + { + if(mOutput->isInitialized()) + mOutput->pauseAllSounds(); + } + + void SoundManager::resumeAllSounds() + { + if(mOutput->isInitialized()) + mOutput->resumeAllSounds(); + } + + void SoundManager::updateRegionSound(float duration) { MWWorld::Ptr::CellStore *current = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index a84aa3b9a..aaa362d84 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -127,6 +127,12 @@ namespace MWSound virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? + virtual void pauseAllSounds(); + ///< Pauses all currently playing sounds, including music. + + virtual void resumeAllSounds(); + ///< Resumes all previously paused sounds. + virtual void update(float duration); virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up); From 18d8c767bd8c521b2f06eecadd762de00b516742 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 12 Dec 2012 15:15:55 +0100 Subject: [PATCH 076/916] fix a bunch of warnings, improved error handling, initialize texture to black --- apps/openmw/mwrender/videoplayer.cpp | 268 +++++++++++++------------ apps/openmw/mwrender/videoplayer.hpp | 11 +- apps/openmw/mwsound/ffmpeg_decoder.cpp | 6 +- 3 files changed, 154 insertions(+), 131 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 46fa4b9e9..07fa723e2 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -125,21 +125,23 @@ namespace MWRender } return ret; } - static void packet_queue_flush(PacketQueue *q) { + + void PacketQueue::flush() { AVPacketList *pkt, *pkt1; - q->mutex.lock(); - for(pkt = q->first_pkt; pkt != NULL; pkt = pkt1) { + this->mutex.lock(); + for(pkt = this->first_pkt; pkt != NULL; pkt = pkt1) { pkt1 = pkt->next; av_free_packet(&pkt->pkt); av_freep(&pkt); } - q->last_pkt = NULL; - q->first_pkt = NULL; - q->nb_packets = 0; - q->size = 0; - q->mutex.unlock (); + this->last_pkt = NULL; + this->first_pkt = NULL; + this->nb_packets = 0; + this->size = 0; + this->mutex.unlock (); } + double get_audio_clock(VideoState *is) { double pts; int hw_buf_size, bytes_per_sec, n; @@ -279,7 +281,7 @@ namespace MWRender is->audio_pkt_data = pkt->data; is->audio_pkt_size = pkt->size; /* if update, update the audio clock w/pts */ - if(pkt->pts != AV_NOPTS_VALUE) { + if((uint64_t)pkt->pts != AV_NOPTS_VALUE) { is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; } } @@ -349,7 +351,7 @@ namespace MWRender if (is->video_st->codec->width != 0 && is->video_st->codec->height != 0) { Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().getByName("VideoTexture"); - if (texture.isNull () || texture->getWidth() != is->video_st->codec->width || texture->getHeight() != is->video_st->codec->height) + if (texture.isNull () || static_cast(texture->getWidth()) != is->video_st->codec->width || static_cast(texture->getHeight()) != is->video_st->codec->height) { Ogre::TextureManager::getSingleton ().remove ("VideoTexture"); texture = Ogre::TextureManager::getSingleton().createManual( @@ -364,6 +366,7 @@ namespace MWRender Ogre::PixelBox pb(is->video_st->codec->width, is->video_st->codec->height, 1, Ogre::PF_BYTE_RGBA, vp->data); Ogre::HardwarePixelBufferSharedPtr buffer = texture->getBuffer(); buffer->blitFromMemory(pb); + is->display_ready = 1; } free(vp->data); @@ -527,7 +530,7 @@ namespace MWRender int video_thread(void *arg) { VideoState *is = (VideoState *)arg; AVPacket pkt1, *packet = &pkt1; - int len1, frameFinished; + int frameFinished; AVFrame *pFrame; double pts; @@ -547,12 +550,15 @@ namespace MWRender // Save global pts to be stored in pFrame global_video_pkt_pts = packet->pts; // Decode video frame - len1 = avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, - packet); - if(packet->dts == AV_NOPTS_VALUE + if (avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, + packet) < 0) + { + throw std::runtime_error("Error decoding video frame"); + } + if((uint64_t)packet->dts == AV_NOPTS_VALUE && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) { pts = *(uint64_t *)pFrame->opaque; - } else if(packet->dts != AV_NOPTS_VALUE) { + } else if((uint64_t)packet->dts != AV_NOPTS_VALUE) { pts = packet->dts; } else { pts = 0; @@ -586,7 +592,7 @@ namespace MWRender AVCodec *codec; SDL_AudioSpec wanted_spec, spec; - if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) { + if(stream_index < 0 || stream_index >= static_cast(pFormatCtx->nb_streams)) { return -1; } @@ -650,127 +656,141 @@ namespace MWRender break; } - + return 0; } int decode_interrupt_cb(void) { return (global_video_state && global_video_state->quit); } - int decode_thread(void *arg) { - + int decode_thread(void *arg) + { VideoState *is = (VideoState *)arg; - AVFormatContext *pFormatCtx = avformat_alloc_context (); - AVPacket pkt1, *packet = &pkt1; - - int video_index = -1; - int audio_index = -1; - int i; - - is->videoStream=-1; - is->audioStream=-1; - is->quit = 0; - - Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton ().openResource (is->resourceName); - if(stream.isNull ()) - throw std::runtime_error("Failed to open video resource"); - is->stream = stream; - - AVIOContext *ioContext = 0; - - ioContext = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); - if (!ioContext) - throw std::runtime_error("Failed to allocate ioContext "); - - pFormatCtx->pb = ioContext; - - global_video_state = is; - // will interrupt blocking functions if we quit! - //url_set_interrupt_cb(decode_interrupt_cb); - - // Open video file - /// \todo leak here, ffmpeg or valgrind bug ? - if (avformat_open_input(&pFormatCtx, is->resourceName.c_str(), NULL, NULL)) - throw std::runtime_error("Failed to open video input"); - - // Retrieve stream information - if(avformat_find_stream_info(pFormatCtx, NULL)<0) - throw std::runtime_error("Failed to retrieve stream information"); - - // Dump information about file onto standard error - av_dump_format(pFormatCtx, 0, is->resourceName.c_str(), 0); - - for(i=0; inb_streams; i++) { - if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && - video_index < 0) { - video_index=i; - } - if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && - audio_index < 0) { - audio_index=i; - } - } - - if(audio_index >= 0) { - stream_component_open(is, audio_index, pFormatCtx); - } - if(video_index >= 0) { - stream_component_open(is, video_index, pFormatCtx); - } - - if(is->videoStream >= 0 /*|| is->audioStream < 0*/) + try { + AVFormatContext *pFormatCtx = avformat_alloc_context (); + AVPacket pkt1, *packet = &pkt1; - // main decode loop + int video_index = -1; + int audio_index = -1; + unsigned int i; - for(;;) { - if(is->quit) { - break; + is->videoStream=-1; + is->audioStream=-1; + is->quit = 0; + + Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton ().openResource (is->resourceName); + if(stream.isNull ()) + throw std::runtime_error("Failed to open video resource"); + is->stream = stream; + + AVIOContext *ioContext = 0; + + ioContext = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if (!ioContext) + throw std::runtime_error("Failed to allocate ioContext "); + + pFormatCtx->pb = ioContext; + + global_video_state = is; + // will interrupt blocking functions if we quit! + //url_set_interrupt_cb(decode_interrupt_cb); + + // Open video file + /// \todo leak here, ffmpeg or valgrind bug ? + if (avformat_open_input(&pFormatCtx, is->resourceName.c_str(), NULL, NULL)) + throw std::runtime_error("Failed to open video input"); + + // Retrieve stream information + if(avformat_find_stream_info(pFormatCtx, NULL)<0) + throw std::runtime_error("Failed to retrieve stream information"); + + // Dump information about file onto standard error + av_dump_format(pFormatCtx, 0, is->resourceName.c_str(), 0); + + for(i=0; inb_streams; i++) { + if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && + video_index < 0) { + video_index=i; } - if( (is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || - is->videoq.size > MAX_VIDEOQ_SIZE) { - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - continue; - } - if(av_read_frame(pFormatCtx, packet) < 0) { - break; - } - // Is this a packet from the video stream? - if(packet->stream_index == is->videoStream) { - packet_queue_put(&is->videoq, packet); - } else if(packet->stream_index == is->audioStream) { - packet_queue_put(&is->audioq, packet); - } else { - av_free_packet(packet); + if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && + audio_index < 0) { + audio_index=i; } } - /* all done - wait for it */ - while(!is->quit) { - // EOF reached, all packets processed, we can exit now - if (is->audioq.nb_packets == 0 && is->videoq.nb_packets == 0) - break; - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + + if(audio_index >= 0) { + stream_component_open(is, audio_index, pFormatCtx); } + if(video_index >= 0) { + stream_component_open(is, video_index, pFormatCtx); + } + + if(is->videoStream >= 0 /*|| is->audioStream < 0*/) + { + + // main decode loop + + for(;;) { + if(is->quit) { + break; + } + if( (is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || + is->videoq.size > MAX_VIDEOQ_SIZE) { + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + continue; + } + if(av_read_frame(pFormatCtx, packet) < 0) { + break; + } + // Is this a packet from the video stream? + if(packet->stream_index == is->videoStream) { + packet_queue_put(&is->videoq, packet); + } else if(packet->stream_index == is->audioStream) { + packet_queue_put(&is->audioq, packet); + } else { + av_free_packet(packet); + } + } + /* all done - wait for it */ + while(!is->quit) { + // EOF reached, all packets processed, we can exit now + if (is->audioq.nb_packets == 0 && is->videoq.nb_packets == 0) + break; + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + } + + + is->quit = 1; + + is->audioq.cond.notify_one (); + is->videoq.cond.notify_one (); + + is->video_thread.join(); + + if (is->audioStream >= 0) + avcodec_close(is->audio_st->codec); + if (is->videoStream >= 0) + avcodec_close(is->video_st->codec); + + sws_freeContext (is->sws_context); + + avformat_close_input(&pFormatCtx); + pFormatCtx = NULL; + + av_free(ioContext); + } + catch (std::runtime_error& e) + { + std::cerr << "An error occured playing the video: " << e.what () << std::endl; + is->quit = 1; + } + catch (Ogre::Exception& e) + { + std::cerr << "An error occured playing the video: " << e.getFullDescription () << std::endl; + is->quit = 1; } - - is->quit = 1; - - is->audioq.cond.notify_one (); - is->videoq.cond.notify_one (); - - is->video_thread.join(); - - if (is->audioStream >= 0) - avcodec_close(is->audio_st->codec); - if (is->videoStream >= 0) - avcodec_close(is->video_st->codec); - - sws_freeContext (is->sws_context); - - av_close_input_file(pFormatCtx); - pFormatCtx = NULL; - - av_free(ioContext); return 0; } @@ -857,8 +877,10 @@ namespace MWRender close(); } - if (!Ogre::TextureManager::getSingleton ().getByName ("VideoTexture").isNull ()) + if (mState && mState->display_ready && !Ogre::TextureManager::getSingleton ().getByName ("VideoTexture").isNull ()) mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("VideoTexture"); + else + mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("black.png"); } void VideoPlayer::close() diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 67a22a506..d9dc6ded0 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -48,6 +48,8 @@ namespace MWRender boost::mutex mutex; boost::condition_variable cond; + + void flush (); }; struct VideoPicture { VideoPicture () : @@ -58,8 +60,6 @@ namespace MWRender double pts; }; - static void packet_queue_flush(PacketQueue *q); - struct VideoState { VideoState () : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock(0), @@ -67,14 +67,14 @@ namespace MWRender audio_pkt_data(NULL), audio_pkt_size(0), audio_hw_buf_size(0), audio_diff_cum(0), audio_diff_avg_coef(0), audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), frame_last_delay(0), video_clock(0), video_current_pts(0), video_current_pts_time(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), - pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), sws_context(NULL) + pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), sws_context(NULL), display_ready(0) {} ~VideoState() { - packet_queue_flush (&audioq); - packet_queue_flush (&videoq); + audioq.flush (); + videoq.flush(); if (pictq_size >= 1) free (pictq[0].data); @@ -126,6 +126,7 @@ namespace MWRender int quit; int refresh; + int display_ready; }; enum { AV_SYNC_AUDIO_MASTER, diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 5f61ab8f0..9d5942111 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -277,7 +277,7 @@ void FFmpeg_Decoder::open(const std::string &fname) ss << stream->mCodecCtx->codec_id; fail(ss.str()); } - if(avcodec_open(stream->mCodecCtx, codec) < 0) + if(avcodec_open2(stream->mCodecCtx, codec, NULL) < 0) fail("Failed to open audio codec " + std::string(codec->long_name)); stream->mDecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); @@ -293,7 +293,7 @@ void FFmpeg_Decoder::open(const std::string &fname) } catch(std::exception &e) { - av_close_input_file(mFormatCtx); + avformat_close_input(&mFormatCtx); mFormatCtx = NULL; throw; } @@ -317,7 +317,7 @@ void FFmpeg_Decoder::close() AVIOContext* context = mFormatCtx->pb; av_free(context); mFormatCtx->pb = NULL; - av_close_input_file(mFormatCtx); + avformat_close_input(&mFormatCtx); } mFormatCtx = NULL; From cc18b30e17fe054b4c7b6bd41baafe3aeaa8799a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 12 Dec 2012 22:36:20 +0100 Subject: [PATCH 077/916] open sub view on double click in report view --- apps/opencs/model/tools/reportmodel.cpp | 5 +++++ apps/opencs/model/tools/reportmodel.hpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 ++++ apps/opencs/view/doc/subview.hpp | 4 ++++ apps/opencs/view/doc/view.cpp | 4 ++++ apps/opencs/view/doc/view.hpp | 6 ++++-- apps/opencs/view/tools/reportsubview.cpp | 11 +++++++++-- apps/opencs/view/tools/reportsubview.hpp | 13 +++++++++++++ 8 files changed, 45 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index f142d7669..b12531875 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -63,4 +63,9 @@ void CSMTools::ReportModel::add (const std::string& row) mRows.push_back (std::make_pair (row.substr (0, index), row.substr (index+1))); endInsertRows(); +} + +const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) const +{ + return mRows.at (row).first; } \ No newline at end of file diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 8814b6d49..55c25d907 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -29,6 +29,8 @@ namespace CSMTools virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); void add (const std::string& row); + + const CSMWorld::UniversalId& getUniversalId (int row) const; }; } diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 14c086510..8f43bf083 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace CSMWorld { class UniversalId @@ -87,4 +89,6 @@ namespace CSMWorld std::ostream& operator< (std::ostream& stream, const UniversalId& universalId); } +Q_DECLARE_METATYPE (CSMWorld::UniversalId) + #endif diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 50ec511ab..985c5eb3c 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -35,6 +35,10 @@ namespace CSVDoc CSMWorld::UniversalId getUniversalId() const; virtual void setEditLock (bool locked) = 0; + + signals: + + void focusId (const CSMWorld::UniversalId& universalId); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 4ffd9d749..13edb6e74 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -188,6 +188,10 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) SubView *view = mSubViewFactory.makeSubView (id, *mDocument); addDockWidget (Qt::TopDockWidgetArea, view); + + connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, + SLOT (addSubView (const CSMWorld::UniversalId&))); + view->show(); } diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index f7d4dd373..b1dedafe9 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -80,12 +80,14 @@ namespace CSVDoc void updateProgress (int current, int max, int type, int threads); - void addSubView (const CSMWorld::UniversalId& id); - signals: void newDocumentRequest(); + public slots: + + void addSubView (const CSMWorld::UniversalId& id); + private slots: void newView(); diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index 3c9283684..fe1be85d7 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -7,19 +7,26 @@ #include "../../model/tools/reportmodel.hpp" CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id) +: CSVDoc::SubView (id), mModel (document.getReport (id)) { setWidget (mTable = new QTableView (this)); - mTable->setModel (document.getReport (id)); + mTable->setModel (mModel); mTable->horizontalHeader()->setResizeMode (QHeaderView::Interactive); mTable->verticalHeader()->hide(); mTable->setSortingEnabled (true); mTable->setSelectionBehavior (QAbstractItemView::SelectRows); mTable->setSelectionMode (QAbstractItemView::ExtendedSelection); + + connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&))); } void CSVTools::ReportSubView::setEditLock (bool locked) { // ignored. We don't change document state anyway. +} + +void CSVTools::ReportSubView::show (const QModelIndex& index) +{ + focusId (mModel->getUniversalId (index.row())); } \ No newline at end of file diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp index f81f3c386..626ceb663 100644 --- a/apps/opencs/view/tools/reportsubview.hpp +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -4,18 +4,27 @@ #include "../doc/subview.hpp" class QTableView; +class QModelIndex; namespace CSMDoc { class Document; } +namespace CSMTools +{ + class ReportModel; +} + namespace CSVTools { class Table; class ReportSubView : public CSVDoc::SubView { + Q_OBJECT + + CSMTools::ReportModel *mModel; QTableView *mTable; public: @@ -23,6 +32,10 @@ namespace CSVTools ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); virtual void setEditLock (bool locked); + + private slots: + + void show (const QModelIndex& index); }; } From 34e36fb85269775821efe8a07f7f47518bd1dbb1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2012 16:50:35 -0800 Subject: [PATCH 078/916] Add a method to get the time offset from sounds --- apps/openmw/mwsound/openal_output.cpp | 17 +++++++++++++++++ apps/openmw/mwsound/sound.hpp | 1 + 2 files changed, 18 insertions(+) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bc6102beb..4c62bb10f 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -95,6 +95,7 @@ public: virtual void stop(); virtual bool isPlaying(); + virtual double getTimeOffset(); virtual void update(); void play(); @@ -259,6 +260,11 @@ bool OpenAL_SoundStream::isPlaying() return !mIsFinished; } +double OpenAL_SoundStream::getTimeOffset() +{ + return 0.0; +} + void OpenAL_SoundStream::update() { ALfloat gain = mVolume*mBaseVolume; @@ -348,6 +354,7 @@ public: virtual void stop(); virtual bool isPlaying(); + virtual double getTimeOffset(); virtual void update(); }; @@ -396,6 +403,16 @@ bool OpenAL_Sound::isPlaying() return state==AL_PLAYING || state==AL_PAUSED; } +double OpenAL_Sound::getTimeOffset() +{ + ALfloat t; + + alGetSourcef(mSource, AL_SEC_OFFSET, &t); + throwALerror(); + + return t; +} + void OpenAL_Sound::update() { ALfloat gain = mVolume*mBaseVolume; diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 729147f75..1b6f50ff4 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -26,6 +26,7 @@ namespace MWSound public: virtual void stop() = 0; virtual bool isPlaying() = 0; + virtual double getTimeOffset() = 0; void setPosition(const Ogre::Vector3 &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } From 1fb9eef27b511281e7c179012a7082dcc169a5b7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2012 22:02:33 -0800 Subject: [PATCH 079/916] Detach the thread used for frame timing --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 9cfe703b4..27fb89130 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -336,7 +336,7 @@ namespace MWRender //SDL_AddTimer(delay, sdl_refresh_timer_cb, is); //is->refresh_queue.push_back (delay); boost::system_time t = boost::get_system_time() + boost::posix_time::milliseconds(delay); - boost::thread (boost::bind(&timer_callback, t, is)); + boost::thread (boost::bind(&timer_callback, t, is)).detach(); } void video_display(VideoState *is) From 9c831d303983c5bf77f92ec05d7f1ae8555ed1d9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2012 22:19:44 -0800 Subject: [PATCH 080/916] Add a decoder method to get the "file" name --- apps/openmw/mwsound/audiere_decoder.cpp | 11 ++++++++++- apps/openmw/mwsound/audiere_decoder.hpp | 1 + apps/openmw/mwsound/ffmpeg_decoder.cpp | 5 +++++ apps/openmw/mwsound/ffmpeg_decoder.hpp | 1 + apps/openmw/mwsound/mpgsnd_decoder.cpp | 5 +++++ apps/openmw/mwsound/sound_decoder.hpp | 1 + 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/audiere_decoder.cpp b/apps/openmw/mwsound/audiere_decoder.cpp index 4e73573a7..c9b3d11d1 100644 --- a/apps/openmw/mwsound/audiere_decoder.cpp +++ b/apps/openmw/mwsound/audiere_decoder.cpp @@ -53,6 +53,9 @@ public: : mStream(stream), refs(1) { } virtual ~OgreFile() { } + + Ogre::String getName() + { return mStream->getName(); } }; @@ -60,7 +63,7 @@ void Audiere_Decoder::open(const std::string &fname) { close(); - audiere::FilePtr file(new OgreFile(mResourceMgr.openResource(fname))); + mSoundFile = audiere::FilePtr(new OgreFile(mResourceMgr.openResource(fname))); mSoundSource = audiere::OpenSampleSource(file); int channels, srate; @@ -86,9 +89,15 @@ void Audiere_Decoder::open(const std::string &fname) void Audiere_Decoder::close() { + mSoundFile = NULL; mSoundSource = NULL; } +std::string Audiere_Decoder::getName() +{ + return mSoundFile->getName(); +} + void Audiere_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { *samplerate = mSampleRate; diff --git a/apps/openmw/mwsound/audiere_decoder.hpp b/apps/openmw/mwsound/audiere_decoder.hpp index 0ad026d51..1e1528880 100644 --- a/apps/openmw/mwsound/audiere_decoder.hpp +++ b/apps/openmw/mwsound/audiere_decoder.hpp @@ -12,6 +12,7 @@ namespace MWSound { class Audiere_Decoder : public Sound_Decoder { + audiere::FilePtr mSoundFile; audiere::SampleSourcePtr mSoundSource; int mSampleRate; SampleType mSampleType; diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 9d5942111..6b3a7f9cd 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -324,6 +324,11 @@ void FFmpeg_Decoder::close() mDataStream.setNull(); } +std::string FFmpeg_Decoder::getName() +{ + return mFormatCtx->filename; +} + void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { if(mStreams.empty()) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index a6e80fc9b..88115ce3f 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -36,6 +36,7 @@ namespace MWSound virtual void open(const std::string &fname); virtual void close(); + virtual std::string getName(); virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual size_t read(char *buffer, size_t bytes); diff --git a/apps/openmw/mwsound/mpgsnd_decoder.cpp b/apps/openmw/mwsound/mpgsnd_decoder.cpp index 7f7a84889..4ec11b349 100644 --- a/apps/openmw/mwsound/mpgsnd_decoder.cpp +++ b/apps/openmw/mwsound/mpgsnd_decoder.cpp @@ -155,6 +155,11 @@ void MpgSnd_Decoder::close() mDataStream.setNull(); } +std::string MpgSnd_Decoder::getName() +{ + return mDataStream->getName(); +} + void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { if(!mSndFile && !mMpgFile) diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 9c28d5ff5..d228a5e98 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -29,6 +29,7 @@ namespace MWSound virtual void open(const std::string &fname) = 0; virtual void close() = 0; + virtual std::string getName() = 0; virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; virtual size_t read(char *buffer, size_t bytes) = 0; From 86bf6388c64ad0784bd428de479ce9eb81edb389 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2012 22:32:02 -0800 Subject: [PATCH 081/916] Pass a decoder to the playStream sound output method --- apps/openmw/mwsound/openal_output.cpp | 8 +++----- apps/openmw/mwsound/openal_output.hpp | 4 ++-- apps/openmw/mwsound/sound_output.hpp | 4 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +++++- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 4c62bb10f..521e6c357 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -764,7 +764,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre } -MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch, int flags) +MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, float pitch, int flags) { boost::shared_ptr sound; ALuint src; @@ -774,12 +774,10 @@ MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volu src = mFreeSources.front(); mFreeSources.pop_front(); + if((flags&MWBase::SoundManager::Play_Loop)) + std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - if((flags&MWBase::SoundManager::Play_Loop)) - std::cout <<"Warning: cannot loop stream "<open(fname); sound.reset(new OpenAL_SoundStream(*this, src, decoder)); } catch(std::exception &e) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 867150741..ce126035f 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -47,8 +47,8 @@ namespace MWSound virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags); virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, - float volume, float pitch, float min, float max, int flags); - virtual MWBase::SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags); + float volume, float pitch, float min, float max, int flags); + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 1cc45559b..1229f87d0 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -26,8 +26,8 @@ namespace MWSound virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0; virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, - float volume, float pitch, float min, float max, int flags) = 0; - virtual MWBase::SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags) = 0; + float volume, float pitch, float min, float max, int flags) = 0; + virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0; virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1414dbb76..2a489a789 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -167,7 +167,11 @@ namespace MWSound { float basevol = mMasterVolume * mMusicVolume; stopMusic(); - mMusic = mOutput->streamSound(filename, basevol, 1.0f, Play_NoEnv); + + DecoderPtr decoder = getDecoder(); + decoder->open(filename); + + mMusic = mOutput->streamSound(decoder, basevol, 1.0f, Play_NoEnv); mMusic->mBaseVolume = basevol; mMusic->mFlags = Play_NoEnv; } From 1571243ef00dce1c22753c791cfb879f2b50ef2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 12 Dec 2012 23:13:35 -0800 Subject: [PATCH 082/916] Implement getTimeOffset for OpenAL_SoundStream --- apps/openmw/mwsound/openal_output.cpp | 132 ++++++++++++++++++-------- 1 file changed, 91 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 521e6c357..658483b02 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -65,6 +65,18 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) return AL_NONE; } +static ALint getBufferSampleCount(ALuint buf) +{ + ALint size, bits, channels; + + alGetBufferi(buf, AL_SIZE, &size); + alGetBufferi(buf, AL_BITS, &bits); + alGetBufferi(buf, AL_CHANNELS, &channels); + throwALerror(); + + return size / channels * 8 / bits; +} + // // A streaming OpenAL sound. // @@ -82,6 +94,9 @@ class OpenAL_SoundStream : public Sound ALsizei mSampleRate; ALuint mBufferSize; + ALuint mSamplesTotal; + ALuint mSamplesQueued; + DecoderPtr mDecoder; volatile bool mIsFinished; @@ -172,7 +187,8 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder) - : mOutput(output), mSource(src), mDecoder(decoder), mIsFinished(true) + : mOutput(output), mSource(src), mSamplesTotal(0), mSamplesQueued(0), + mDecoder(decoder), mIsFinished(true) { throwALerror(); @@ -215,16 +231,19 @@ OpenAL_SoundStream::~OpenAL_SoundStream() void OpenAL_SoundStream::play() { std::vector data(mBufferSize); + ALuint count = 0; alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); throwALerror(); + mSamplesQueued = 0; for(ALuint i = 0;i < sNumBuffers;i++) { size_t got; got = mDecoder->read(&data[0], data.size()); alBufferData(mBuffers[i], mFormat, &data[0], got, mSampleRate); + count += getBufferSampleCount(mBuffers[i]); } throwALerror(); @@ -232,6 +251,9 @@ void OpenAL_SoundStream::play() alSourcePlay(mSource); throwALerror(); + mSamplesTotal += count; + mSamplesQueued = count; + mIsFinished = false; mOutput.mStreamThread->add(this); } @@ -244,8 +266,10 @@ void OpenAL_SoundStream::stop() alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); throwALerror(); + mSamplesQueued = 0; mDecoder->rewind(); + mSamplesTotal = 0; } bool OpenAL_SoundStream::isPlaying() @@ -262,7 +286,21 @@ bool OpenAL_SoundStream::isPlaying() double OpenAL_SoundStream::getTimeOffset() { - return 0.0; + ALint state = AL_STOPPED; + ALfloat offset = 0.0f; + double t; + + mOutput.mStreamThread->mMutex.lock(); + alGetSourcef(mSource, AL_SEC_OFFSET, &offset); + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + if(state == AL_PLAYING || state == AL_PAUSED) + t = (double)(mSamplesTotal - mSamplesQueued)/(double)mSampleRate + offset; + else + t = (double)mSamplesTotal / (double)mSampleRate; + mOutput.mStreamThread->mMutex.unlock(); + + throwALerror(); + return t; } void OpenAL_SoundStream::update() @@ -285,52 +323,64 @@ void OpenAL_SoundStream::update() bool OpenAL_SoundStream::process() { - bool finished = mIsFinished; - ALint processed, state; + try { + bool finished = mIsFinished; + ALint samples_unqueued = 0; + ALint samples_queued = 0; + ALint processed, state; - alGetSourcei(mSource, AL_SOURCE_STATE, &state); - alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed); - throwALerror(); - - if(processed > 0) - { - std::vector data(mBufferSize); - do { - ALuint bufid; - size_t got; - - alSourceUnqueueBuffers(mSource, 1, &bufid); - processed--; - - if(finished) - continue; - - got = mDecoder->read(&data[0], data.size()); - finished = (got < data.size()); - if(got > 0) - { - alBufferData(bufid, mFormat, &data[0], got, mSampleRate); - alSourceQueueBuffers(mSource, 1, &bufid); - } - } while(processed > 0); + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed); throwALerror(); - } - if(state != AL_PLAYING && state != AL_PAUSED) - { - ALint queued; - - alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); - throwALerror(); - if(queued > 0) + if(processed > 0) { - alSourcePlay(mSource); + std::vector data(mBufferSize); + do { + ALuint bufid = 0; + size_t got; + + alSourceUnqueueBuffers(mSource, 1, &bufid); + samples_unqueued += getBufferSampleCount(bufid); + processed--; + + if(finished) + continue; + + got = mDecoder->read(&data[0], data.size()); + finished = (got < data.size()); + if(got > 0) + { + alBufferData(bufid, mFormat, &data[0], got, mSampleRate); + alSourceQueueBuffers(mSource, 1, &bufid); + samples_queued += getBufferSampleCount(bufid); + } + } while(processed > 0); throwALerror(); } - } - mIsFinished = finished; - return !finished; + if(state != AL_PLAYING && state != AL_PAUSED) + { + ALint queued = 0; + + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + if(queued > 0) + alSourcePlay(mSource); + throwALerror(); + } + + mSamplesQueued -= samples_unqueued; + mSamplesQueued += samples_queued; + mSamplesTotal += samples_queued; + mIsFinished = finished; + } + catch(std::exception &e) { + std::cout<< "Error updating stream \""<getName()<<"\"" < Date: Thu, 13 Dec 2012 00:05:57 -0800 Subject: [PATCH 083/916] Add a method to play an audio track with a custom decoder --- apps/openmw/mwbase/soundmanager.hpp | 5 +++++ apps/openmw/mwsound/soundmanagerimp.cpp | 20 ++++++++++++++++++++ apps/openmw/mwsound/soundmanagerimp.hpp | 5 +++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 2fa98cfee..8d204bad4 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -22,6 +22,8 @@ namespace MWWorld namespace MWSound { class Sound; + class Sound_Decoder; + typedef boost::shared_ptr DecoderPtr; } namespace MWBase @@ -89,6 +91,9 @@ namespace MWBase virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0; ///< Stop an actor speaking + virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder) = 0; + ///< Play a 2D audio track, using a custom decoder + virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal) = 0; ///< Play a sound, independently of 3D-position diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2a489a789..6bb3d59dd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -275,6 +275,26 @@ namespace MWSound } + MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder) + { + MWBase::SoundPtr track; + if(!mOutput->isInitialized()) + return track; + try + { + float basevol = mMasterVolume; + + track = mOutput->streamSound(decoder, basevol, 1.0f, Play_NoEnv); + track->mBaseVolume = basevol; + track->mFlags = Play_NoEnv; + } + catch(std::exception &e) + { + std::cout <<"Sound Error: "< DecoderPtr; - enum Environment { Env_Normal, Env_Underwater @@ -105,6 +103,9 @@ namespace MWSound virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); ///< Stop an actor speaking + virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder); + ///< Play a 2D audio track, using a custom decoder + virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal); ///< Play a sound, independently of 3D-position From 1ffaf6625a37ba8ba0f1463926dc8b94e2900623 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 01:42:20 -0800 Subject: [PATCH 084/916] Remove SDL for playing movie audio and prepare for using an audio track This breaks audio playback on movies --- apps/openmw/mwrender/videoplayer.cpp | 320 ++++++++++++++++----------- apps/openmw/mwrender/videoplayer.hpp | 71 +++--- 2 files changed, 225 insertions(+), 166 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 27fb89130..fa179f8b1 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -4,7 +4,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" - +#include "../mwsound/sound_decoder.hpp" +#include "../mwsound/sound.hpp" namespace MWRender @@ -143,19 +144,13 @@ namespace MWRender this->mutex.unlock (); } - double get_audio_clock(VideoState *is) { - double pts; - - pts = is->audio_clock; /* maintained in the audio thread */ - if(is->audio_st) { - int n = is->audio_st->codec->channels * 2; - int bytes_per_sec = is->audio_st->codec->sample_rate * n; - int hw_buf_size = is->audio_buf_size - is->audio_buf_index; - pts -= (double)hw_buf_size / bytes_per_sec; - } - return pts; + double get_audio_clock(VideoState *is) + { + return is->AudioTrack->getTimeOffset(); } - double get_video_clock(VideoState *is) { + + double get_video_clock(VideoState *is) + { double delta; delta = (av_gettime() - is->video_current_pts_time) / 1000000.0; @@ -173,86 +168,110 @@ namespace MWRender return get_external_clock(is); } } + +class MovieAudioDecoder : public MWSound::Sound_Decoder +{ + static void fail(const std::string &str) + { + throw std::runtime_error(str); + } + + VideoState *is; + /* Add or subtract samples to get a better sync, return new - audio buffer size */ - int synchronize_audio(VideoState *is, short *samples, - int samples_size, double pts) { - int n; - double ref_clock; + * audio buffer size */ + int synchronize_audio(uint8_t *samples, int samples_size, double pts) + { + if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) + return samples_size; + + double diff, avg_diff, ref_clock; + int wanted_size, min_size, max_size, n; + // int nb_samples; n = 2 * is->audio_st->codec->channels; - if(is->av_sync_type != AV_SYNC_AUDIO_MASTER) { - double diff, avg_diff; - int wanted_size, min_size, max_size; - // int nb_samples; + ref_clock = get_master_clock(is); + diff = get_audio_clock(is) - ref_clock; + if(diff < AV_NOSYNC_THRESHOLD) + { + // accumulate the diffs + is->audio_diff_cum = diff + is->audio_diff_avg_coef * + is->audio_diff_cum; + if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) + is->audio_diff_avg_count++; + else + { + avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); + if(fabs(avg_diff) >= is->audio_diff_threshold) + { + wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); + min_size = samples_size * ((100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100); + max_size = samples_size * ((100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100); - ref_clock = get_master_clock(is); - diff = get_audio_clock(is) - ref_clock; - if(diff < AV_NOSYNC_THRESHOLD) { - // accumulate the diffs - is->audio_diff_cum = diff + is->audio_diff_avg_coef * - is->audio_diff_cum; - if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) { - is->audio_diff_avg_count++; - } else { - avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); - if(fabs(avg_diff) >= is->audio_diff_threshold) { - wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); - min_size = samples_size * ((100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100); - max_size = samples_size * ((100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100); - if(wanted_size < min_size) { - wanted_size = min_size; - } else if (wanted_size > max_size) { - wanted_size = max_size; - } - if(wanted_size < samples_size) { - /* remove samples */ - samples_size = wanted_size; - } else if(wanted_size > samples_size) { - uint8_t *samples_end, *q; - int nb; - /* add samples by copying final sample*/ - nb = (samples_size - wanted_size); - samples_end = (uint8_t *)samples + samples_size - n; - q = samples_end + n; - while(nb > 0) { - memcpy(q, samples_end, n); - q += n; - nb -= n; - } - samples_size = wanted_size; + if(wanted_size < min_size) + wanted_size = min_size; + else if (wanted_size > max_size) + wanted_size = max_size; + + if(wanted_size < samples_size) + { + /* remove samples */ + samples_size = wanted_size; + } + else if(wanted_size > samples_size) + { + uint8_t *samples_end, *q; + int nb; + /* add samples by copying final sample*/ + nb = (samples_size - wanted_size); + samples_end = samples + samples_size - n; + q = samples_end + n; + while(nb > 0) + { + memcpy(q, samples_end, n); + q += n; + nb -= n; } + samples_size = wanted_size; } } - } else { - /* difference is TOO big; reset diff stuff */ - is->audio_diff_avg_count = 0; - is->audio_diff_cum = 0; } } + else + { + /* difference is TOO big; reset diff stuff */ + is->audio_diff_avg_count = 0; + is->audio_diff_cum = 0; + } + return samples_size; } - int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size, double *pts_ptr) { - int len1, data_size, n; + + int audio_decode_frame(uint8_t *audio_buf, int buf_size, double *pts_ptr) + { AVPacket *pkt = &is->audio_pkt; + int len1, data_size, n; double pts; - for(;;) { - while(is->audio_pkt_size > 0) { + for(;;) + { + while(is->audio_pkt_size > 0) + { data_size = buf_size; + len1 = avcodec_decode_audio3(is->audio_st->codec, (int16_t*)audio_buf, &data_size, pkt); - - - if(len1 < 0) { + if(len1 < 0) + { /* if error, skip frame */ is->audio_pkt_size = 0; break; } is->audio_pkt_data += len1; is->audio_pkt_size -= len1; - if(data_size <= 0) { + if(data_size <= 0) + { /* No data yet, get more frames */ continue; } @@ -268,52 +287,111 @@ namespace MWRender if(pkt->data) av_free_packet(pkt); - if(is->quit) { + if(is->quit) return -1; - } + /* next packet */ - if(packet_queue_get(&is->audioq, pkt, 1) < 0) { + if(packet_queue_get(&is->audioq, pkt, 1) < 0) return -1; - } + is->audio_pkt_data = pkt->data; is->audio_pkt_size = pkt->size; /* if update, update the audio clock w/pts */ - if((uint64_t)pkt->pts != AV_NOPTS_VALUE) { + if((uint64_t)pkt->pts != AV_NOPTS_VALUE) is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; - } } } - void audio_callback(void *userdata, Uint8 *stream, int len) { - VideoState *is = (VideoState *)userdata; - int len1, audio_size; - double pts; + void open(const std::string&) + { fail(std::string("Invalid call to ")+__PRETTY_FUNCTION__); } - while(len > 0) { - if(is->audio_buf_index >= is->audio_buf_size) { + void close() { } + + std::string getName() + { return is->stream->getName(); } + + void rewind() { } + +public: + MovieAudioDecoder(VideoState *_is) : is(_is) { } + + void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) + { + if(is->audio_st->codec->sample_fmt == AV_SAMPLE_FMT_U8) + *type = MWSound::SampleType_UInt8; + else if(is->audio_st->codec->sample_fmt == AV_SAMPLE_FMT_S16) + *type = MWSound::SampleType_Int16; + else + fail(std::string("Unsupported sample format: ")+ + av_get_sample_fmt_name(is->audio_st->codec->sample_fmt)); + + if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_MONO) + *chans = MWSound::ChannelConfig_Mono; + else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_STEREO) + *chans = MWSound::ChannelConfig_Stereo; + else if(is->audio_st->codec->channel_layout == 0) + { + /* Unknown channel layout. Try to guess. */ + if(is->audio_st->codec->channels == 1) + *chans = MWSound::ChannelConfig_Mono; + else if(is->audio_st->codec->channels == 2) + *chans = MWSound::ChannelConfig_Stereo; + else + { + std::stringstream sstr("Unsupported raw channel count: "); + sstr << is->audio_st->codec->channels; + fail(sstr.str()); + } + } + else + { + char str[1024]; + av_get_channel_layout_string(str, sizeof(str), is->audio_st->codec->channels, + is->audio_st->codec->channel_layout); + fail(std::string("Unsupported channel layout: ")+str); + } + + *samplerate = is->audio_st->codec->sample_rate; + } + + size_t read(char *stream, size_t len) + { + size_t total = 0; + + while(total < len) + { + if(is->audio_buf_index >= is->audio_buf_size) + { + int audio_size; + double pts; /* We have already sent all our data; get more */ - audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts); - if(audio_size < 0) { - /* If error, output silence */ - is->audio_buf_size = 1024; - memset(is->audio_buf, 0, is->audio_buf_size); - } else { - audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, - audio_size, pts); - is->audio_buf_size = audio_size; + audio_size = audio_decode_frame(is->audio_buf, sizeof(is->audio_buf), &pts); + if(audio_size < 0) + { + /* If error, we're done */ + break; } + + audio_size = synchronize_audio(is->audio_buf, audio_size, pts); + is->audio_buf_size = audio_size; is->audio_buf_index = 0; } - len1 = is->audio_buf_size - is->audio_buf_index; - if(len1 > len) - len1 = len; - memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1); - len -= len1; + + size_t len1 = std::min(is->audio_buf_size - is->audio_buf_index, + len - total); + memcpy(stream, (uint8_t*)is->audio_buf + is->audio_buf_index, len1); + + total += len1; stream += len1; is->audio_buf_index += len1; } + + return total; } +}; + + /* static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) { SDL_Event event; @@ -371,8 +449,8 @@ namespace MWRender } - void video_refresh_timer(void *userdata) { - + void video_refresh_timer(void *userdata) + { VideoState *is = (VideoState *)userdata; VideoPicture *vp; double actual_delay, delay, sync_threshold, ref_clock, diff; @@ -439,8 +517,8 @@ namespace MWRender } } - int queue_picture(VideoState *is, AVFrame *pFrame, double pts) { - + int queue_picture(VideoState *is, AVFrame *pFrame, double pts) + { VideoPicture *vp; /* wait until we have a new pic */ @@ -487,8 +565,8 @@ namespace MWRender return 0; } - double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) { - + double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) + { double frame_delay; if(pts != 0) { @@ -512,14 +590,16 @@ namespace MWRender * buffer. We use this to store the global_pts in * a frame at the time it is allocated. */ - int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) { + int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) + { int ret = avcodec_default_get_buffer(c, pic); uint64_t *pts = (uint64_t*)av_malloc(sizeof(uint64_t)); *pts = global_video_pkt_pts; pic->opaque = pts; return ret; } - void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) { + void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) + { if(pic) av_freep(&pic->opaque); avcodec_default_release_buffer(c, pic); } @@ -583,9 +663,9 @@ namespace MWRender int stream_component_open(VideoState *is, int stream_index, AVFormatContext *pFormatCtx) { + MWSound::DecoderPtr decoder; AVCodecContext *codecCtx; AVCodec *codec; - SDL_AudioSpec wanted_spec, spec; if(stream_index < 0 || stream_index >= static_cast(pFormatCtx->nb_streams)) { return -1; @@ -594,22 +674,9 @@ namespace MWRender // Get a pointer to the codec context for the video stream codecCtx = pFormatCtx->streams[stream_index]->codec; - if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) { - // Set audio settings from codec info - wanted_spec.freq = codecCtx->sample_rate; - wanted_spec.format = AUDIO_S16SYS; - wanted_spec.channels = codecCtx->channels; - wanted_spec.silence = 0; - wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; - wanted_spec.callback = audio_callback; - wanted_spec.userdata = is; + if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) + return -1; - if(SDL_OpenAudio(&wanted_spec, &spec) < 0) { - fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError()); - return -1; - } - is->audio_hw_buf_size = spec.size; - } codec = avcodec_find_decoder(codecCtx->codec_id); if(!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)) { fprintf(stderr, "Unsupported codec!\n"); @@ -627,11 +694,13 @@ namespace MWRender is->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); is->audio_diff_avg_count = 0; /* Correct audio only if larger error than this */ - is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / codecCtx->sample_rate; + is->audio_diff_threshold = 2.0 * 0.1/* 100 ms */; memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); packet_queue_init(&is->audioq); - SDL_PauseAudio(0); + + decoder.reset(new MovieAudioDecoder(is)); + is->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); break; case AVMEDIA_TYPE_VIDEO: is->videoStream = stream_index; @@ -841,17 +910,13 @@ namespace MWRender } mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); + MWBase::Environment::get().getSoundManager()->pauseAllSounds(); mState = new VideoState; // Register all formats and codecs av_register_all(); - MWBase::Environment::get().getSoundManager()->pauseAllSounds(); - if(SDL_Init(SDL_INIT_AUDIO)) { - throw std::runtime_error("Failed to initialize SDL"); - } - mState->refresh = 0; mState->resourceName = resourceName; @@ -869,9 +934,7 @@ namespace MWRender mState->refresh--; } if (mState && mState->quit) - { close(); - } if (mState && mState->display_ready && !Ogre::TextureManager::getSingleton ().getByName ("VideoTexture").isNull ()) mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("VideoTexture"); @@ -888,7 +951,6 @@ namespace MWRender delete mState; mState = NULL; - SDL_CloseAudio(); MWBase::Environment::get().getSoundManager()->resumeAllSounds(); mRectangle->setVisible (false); diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index d9dc6ded0..eac906356 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -16,13 +16,11 @@ extern "C" #include } -#include -#include - #include #include -#define SDL_AUDIO_BUFFER_SIZE 1024 +#include "../mwbase/soundmanager.hpp" + #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) #define AV_SYNC_THRESHOLD 0.01 @@ -33,11 +31,8 @@ extern "C" #define DEFAULT_AV_SYNC_TYPE AV_SYNC_VIDEO_MASTER - namespace MWRender { - - struct PacketQueue { PacketQueue () : first_pkt(NULL), last_pkt(NULL), nb_packets(0), size(0) @@ -64,7 +59,7 @@ namespace MWRender VideoState () : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock(0), external_clock_time(0), audio_clock(0), audio_st(NULL), audio_buf_size(0), - audio_pkt_data(NULL), audio_pkt_size(0), audio_hw_buf_size(0), audio_diff_cum(0), audio_diff_avg_coef(0), + audio_pkt_data(NULL), audio_pkt_size(0), audio_diff_cum(0), audio_diff_avg_coef(0), audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), frame_last_delay(0), video_clock(0), video_current_pts(0), video_current_pts_time(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), sws_context(NULL), display_ready(0) @@ -80,41 +75,44 @@ namespace MWRender free (pictq[0].data); } - int videoStream, audioStream; + int videoStream, audioStream; - int av_sync_type; - double external_clock; /* external clock base */ - int64_t external_clock_time; - double audio_clock; - AVStream *audio_st; - PacketQueue audioq; + int av_sync_type; + double external_clock; /* external clock base */ + int64_t external_clock_time; + + double audio_clock; + AVStream *audio_st; + PacketQueue audioq; DECLARE_ALIGNED(16, uint8_t, audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]); - unsigned int audio_buf_size; - unsigned int audio_buf_index; - AVPacket audio_pkt; - uint8_t *audio_pkt_data; - int audio_pkt_size; - int audio_hw_buf_size; - double audio_diff_cum; /* used for AV difference average computation */ - double audio_diff_avg_coef; - double audio_diff_threshold; - int audio_diff_avg_count; - double frame_timer; - double frame_last_pts; - double frame_last_delay; - double video_clock; /// Date: Thu, 13 Dec 2012 11:24:39 +0100 Subject: [PATCH 085/916] moved two helper classes from view/world/table into a separate translation unit --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/view/world/table.cpp | 94 +------------------------------- apps/opencs/view/world/util.cpp | 57 +++++++++++++++++++ apps/opencs/view/world/util.hpp | 50 +++++++++++++++++ 4 files changed, 110 insertions(+), 95 deletions(-) create mode 100644 apps/opencs/view/world/util.cpp create mode 100644 apps/opencs/view/world/util.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1f9fe85a2..554607c73 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -13,7 +13,7 @@ set (OPENCS_SRC view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp view/doc/subview.cpp - view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp + view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp view/tools/reportsubview.cpp view/tools/subviews.cpp ) @@ -33,7 +33,7 @@ set (OPENCS_HDR view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp view/doc/subview.hpp view/doc/subviewfactoryimp.hpp - view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp + view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp view/tools/reportsubview.hpp view/tools/subviews.hpp ) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 593dc8563..3a5ef7c34 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -1,7 +1,6 @@ #include "table.hpp" -#include #include #include #include @@ -14,98 +13,7 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/record.hpp" -namespace CSVWorld -{ - ///< \brief Getting the data out of an editor widget - /// - /// Really, Qt? Really? - class NastyTableModelHack : public QAbstractTableModel - { - QAbstractItemModel& mModel; - QVariant mData; - - public: - - NastyTableModelHack (QAbstractItemModel& model); - - int rowCount (const QModelIndex & parent = QModelIndex()) const; - - int columnCount (const QModelIndex & parent = QModelIndex()) const; - - QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; - - bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - - QVariant getData() const; - }; - - ///< \brief Use commands instead of manipulating the model directly - class CommandDelegate : public QStyledItemDelegate - { - QUndoStack& mUndoStack; - bool mEditLock; - - public: - - CommandDelegate (QUndoStack& undoStack, QObject *parent); - - void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; - - void setEditLock (bool locked); - }; - -} - -CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) -: mModel (model) -{} - -int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const -{ - return mModel.rowCount (parent); -} - -int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const -{ - return mModel.columnCount (parent); -} - -QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const -{ - return mModel.data (index, role); -} - -bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role) -{ - mData = value; - return true; -} - -QVariant CSVWorld::NastyTableModelHack::getData() const -{ - return mData; -} - -CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) -: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) -{} - -void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, - const QModelIndex& index) const -{ - if (!mEditLock) - { - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); - } - ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. -} - -void CSVWorld::CommandDelegate::setEditLock (bool locked) -{ - mEditLock = locked; -} +#include "util.hpp" void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event) { diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp new file mode 100644 index 000000000..7181dd4d1 --- /dev/null +++ b/apps/opencs/view/world/util.cpp @@ -0,0 +1,57 @@ + +#include "util.hpp" + +#include + +#include "../../model/world/commands.hpp" + +CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) +: mModel (model) +{} + +int CSVWorld::NastyTableModelHack::rowCount (const QModelIndex & parent) const +{ + return mModel.rowCount (parent); +} + +int CSVWorld::NastyTableModelHack::columnCount (const QModelIndex & parent) const +{ + return mModel.columnCount (parent); +} + +QVariant CSVWorld::NastyTableModelHack::data (const QModelIndex & index, int role) const +{ + return mModel.data (index, role); +} + +bool CSVWorld::NastyTableModelHack::setData ( const QModelIndex &index, const QVariant &value, int role) +{ + mData = value; + return true; +} + +QVariant CSVWorld::NastyTableModelHack::getData() const +{ + return mData; +} + +CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) +: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) +{} + +void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + if (!mEditLock) + { + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + } + ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. +} + +void CSVWorld::CommandDelegate::setEditLock (bool locked) +{ + mEditLock = locked; +} \ No newline at end of file diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp new file mode 100644 index 000000000..136583118 --- /dev/null +++ b/apps/opencs/view/world/util.hpp @@ -0,0 +1,50 @@ +#ifndef CSV_WORLD_UTIL_H +#define CSV_WORLD_UTIL_H + +#include +#include + +class QUndoStack; + +namespace CSVWorld +{ + ///< \brief Getting the data out of an editor widget + /// + /// Really, Qt? Really? + class NastyTableModelHack : public QAbstractTableModel + { + QAbstractItemModel& mModel; + QVariant mData; + + public: + + NastyTableModelHack (QAbstractItemModel& model); + + int rowCount (const QModelIndex & parent = QModelIndex()) const; + + int columnCount (const QModelIndex & parent = QModelIndex()) const; + + QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const; + + bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + QVariant getData() const; + }; + + ///< \brief Use commands instead of manipulating the model directly + class CommandDelegate : public QStyledItemDelegate + { + QUndoStack& mUndoStack; + bool mEditLock; + + public: + + CommandDelegate (QUndoStack& undoStack, QObject *parent); + + void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + + void setEditLock (bool locked); + }; +} + +#endif From ba9c5f5b4e0c4feeea646de59e2bb9afc08c5b76 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 02:32:21 -0800 Subject: [PATCH 086/916] Don't initially fill buffers in OpenAL_SoundStream::play --- apps/openmw/mwsound/openal_output.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 658483b02..4bdbf0101 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -230,30 +230,19 @@ OpenAL_SoundStream::~OpenAL_SoundStream() void OpenAL_SoundStream::play() { - std::vector data(mBufferSize); - ALuint count = 0; - alSourceStop(mSource); alSourcei(mSource, AL_BUFFER, 0); throwALerror(); - mSamplesQueued = 0; + for(ALuint i = 0;i < sNumBuffers;i++) - { - size_t got; - got = mDecoder->read(&data[0], data.size()); - alBufferData(mBuffers[i], mFormat, &data[0], got, mSampleRate); - count += getBufferSampleCount(mBuffers[i]); - } + alBufferData(mBuffers[i], mFormat, this, 0, mSampleRate); throwALerror(); alSourceQueueBuffers(mSource, sNumBuffers, mBuffers); alSourcePlay(mSource); throwALerror(); - mSamplesTotal += count; - mSamplesQueued = count; - mIsFinished = false; mOutput.mStreamThread->add(this); } From f067b22b3f6c7c19d3e0cabb9b89b36b8975c287 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 02:33:35 -0800 Subject: [PATCH 087/916] Use a recursive mutex for the OpenAL stream thread --- apps/openmw/mwsound/openal_output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 4bdbf0101..c7b16dd39 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -125,7 +125,7 @@ const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f; struct OpenAL_Output::StreamThread { typedef std::vector StreamVec; StreamVec mStreams; - boost::mutex mMutex; + boost::recursive_mutex mMutex; boost::thread mThread; StreamThread() From d2fbae9760aeaab5b7be705ff736714937ff4ff3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 02:52:37 -0800 Subject: [PATCH 088/916] Init and deinit the VideoState synchronously, and re-enable audio playback --- apps/openmw/mwrender/videoplayer.cpp | 252 ++++++++++++++------------- apps/openmw/mwrender/videoplayer.hpp | 3 +- 2 files changed, 133 insertions(+), 122 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index fa179f8b1..0268539d5 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -68,14 +68,14 @@ namespace MWRender void packet_queue_init(PacketQueue *q) { memset(q, 0, sizeof(PacketQueue)); } - int packet_queue_put(PacketQueue *q, AVPacket *pkt) { + int packet_queue_put(PacketQueue *q, AVPacket *pkt) + { AVPacketList *pkt1; - if(av_dup_packet(pkt) < 0) { + if(av_dup_packet(pkt) < 0) return -1; - } + pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); - if (!pkt1) - return -1; + if(!pkt1) return -1; pkt1->pkt = *pkt; pkt1->next = NULL; @@ -92,21 +92,24 @@ namespace MWRender q->mutex.unlock (); return 0; } - static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) { + static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) + { AVPacketList *pkt1; int ret; boost::unique_lock lock(q->mutex); - for(;;) { - - if(global_video_state->quit) { + for(;;) + { + if(global_video_state->quit) + { ret = -1; break; } pkt1 = q->first_pkt; - if (pkt1) { + if (pkt1) + { q->first_pkt = pkt1->next; if (!q->first_pkt) q->last_pkt = NULL; @@ -116,15 +119,17 @@ namespace MWRender av_free(pkt1); ret = 1; break; - } else if (!block) { + } + + if (!block) + { ret = 0; break; - } else { - - - q->cond.wait(lock); } + + q->cond.wait(lock); } + return ret; } @@ -673,17 +678,15 @@ public: // Get a pointer to the codec context for the video stream codecCtx = pFormatCtx->streams[stream_index]->codec; - - if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) - return -1; - codec = avcodec_find_decoder(codecCtx->codec_id); - if(!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)) { + if(!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)) + { fprintf(stderr, "Unsupported codec!\n"); return -1; } - switch(codecCtx->codec_type) { + switch(codecCtx->codec_type) + { case AVMEDIA_TYPE_AUDIO: is->audioStream = stream_index; is->audio_st = pFormatCtx->streams[stream_index]; @@ -701,7 +704,15 @@ public: decoder.reset(new MovieAudioDecoder(is)); is->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); + if(!is->AudioTrack) + { + is->audioStream = -1; + avcodec_close(is->audio_st->codec); + is->audio_st = NULL; + return -1; + } break; + case AVMEDIA_TYPE_VIDEO: is->videoStream = stream_index; is->video_st = pFormatCtx->streams[stream_index]; @@ -711,11 +722,12 @@ public: is->video_current_pts_time = av_gettime(); packet_queue_init(&is->videoq); - is->video_thread = boost::thread(video_thread, is); + codecCtx->get_buffer = our_get_buffer; codecCtx->release_buffer = our_release_buffer; - + is->video_thread = boost::thread(video_thread, is); break; + default: break; } @@ -732,118 +744,46 @@ public: VideoState *is = (VideoState *)arg; try { - AVFormatContext *pFormatCtx = avformat_alloc_context (); + AVFormatContext *pFormatCtx = is->format_ctx; AVPacket pkt1, *packet = &pkt1; - int video_index = -1; - int audio_index = -1; - unsigned int i; - - is->videoStream=-1; - is->audioStream=-1; - is->quit = 0; - - Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton ().openResource (is->resourceName); - if(stream.isNull ()) - throw std::runtime_error("Failed to open video resource"); - is->stream = stream; - - AVIOContext *ioContext = 0; - - ioContext = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); - if (!ioContext) - throw std::runtime_error("Failed to allocate ioContext "); - - pFormatCtx->pb = ioContext; - - global_video_state = is; - // will interrupt blocking functions if we quit! - //url_set_interrupt_cb(decode_interrupt_cb); - - // Open video file - /// \todo leak here, ffmpeg or valgrind bug ? - if (avformat_open_input(&pFormatCtx, is->resourceName.c_str(), NULL, NULL)) - throw std::runtime_error("Failed to open video input"); - - // Retrieve stream information - if(avformat_find_stream_info(pFormatCtx, NULL)<0) - throw std::runtime_error("Failed to retrieve stream information"); - - // Dump information about file onto standard error - av_dump_format(pFormatCtx, 0, is->resourceName.c_str(), 0); - - for(i=0; inb_streams; i++) { - if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO && - video_index < 0) { - video_index=i; - } - if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO && - audio_index < 0) { - audio_index=i; - } - } - - if(audio_index >= 0) { - stream_component_open(is, audio_index, pFormatCtx); - } - if(video_index >= 0) { - stream_component_open(is, video_index, pFormatCtx); - } - if(is->videoStream >= 0 /*|| is->audioStream < 0*/) { - // main decode loop - - for(;;) { - if(is->quit) { + for(;;) + { + if(is->quit) break; - } - if( (is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || - is->videoq.size > MAX_VIDEOQ_SIZE) { + + if((is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || + is->videoq.size > MAX_VIDEOQ_SIZE) + { boost::this_thread::sleep(boost::posix_time::milliseconds(10)); continue; } - if(av_read_frame(pFormatCtx, packet) < 0) { + + if(av_read_frame(pFormatCtx, packet) < 0) break; - } + // Is this a packet from the video stream? - if(packet->stream_index == is->videoStream) { + if(packet->stream_index == is->videoStream) packet_queue_put(&is->videoq, packet); - } else if(packet->stream_index == is->audioStream) { + else if(packet->stream_index == is->audioStream) packet_queue_put(&is->audioq, packet); - } else { + else av_free_packet(packet); - } } /* all done - wait for it */ - while(!is->quit) { + while(!is->quit) + { // EOF reached, all packets processed, we can exit now - if (is->audioq.nb_packets == 0 && is->videoq.nb_packets == 0) + if(is->audioq.nb_packets == 0 && is->videoq.nb_packets == 0) break; boost::this_thread::sleep(boost::posix_time::milliseconds(100)); } } - is->quit = 1; - - is->audioq.cond.notify_one (); - is->videoq.cond.notify_one (); - - is->video_thread.join(); - - if (is->audioStream >= 0) - avcodec_close(is->audio_st->codec); - if (is->videoStream >= 0) - avcodec_close(is->video_st->codec); - - sws_freeContext (is->sws_context); - - avformat_close_input(&pFormatCtx); - pFormatCtx = NULL; - - av_free(ioContext); } catch (std::runtime_error& e) { @@ -859,6 +799,73 @@ public: return 0; } + void init_state(VideoState *is, const std::string& resourceName) + { + int video_index = -1; + int audio_index = -1; + unsigned int i; + + is->videoStream = -1; + is->audioStream = -1; + is->quit = 0; + + is->stream = Ogre::ResourceGroupManager::getSingleton ().openResource(resourceName); + if(is->stream.isNull()) + throw std::runtime_error("Failed to open video resource"); + + is->format_ctx->pb = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if(!is->format_ctx->pb) + throw std::runtime_error("Failed to allocate ioContext "); + + global_video_state = is; + // will interrupt blocking functions if we quit! + //url_set_interrupt_cb(decode_interrupt_cb); + + // Open video file + /// \todo leak here, ffmpeg or valgrind bug ? + if (avformat_open_input(&is->format_ctx, resourceName.c_str(), NULL, NULL)) + throw std::runtime_error("Failed to open video input"); + + // Retrieve stream information + if(avformat_find_stream_info(is->format_ctx, NULL) < 0) + throw std::runtime_error("Failed to retrieve stream information"); + + // Dump information about file onto standard error + av_dump_format(is->format_ctx, 0, resourceName.c_str(), 0); + + for(i = 0;i < is->format_ctx->nb_streams;i++) + { + if(is->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) + video_index = i; + if(is->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) + audio_index = i; + } + + if(audio_index >= 0) + stream_component_open(is, audio_index, is->format_ctx); + if(video_index >= 0) + stream_component_open(is, video_index, is->format_ctx); + } + + void deinit_state(VideoState *is) + { + is->audioq.cond.notify_one (); + is->videoq.cond.notify_one (); + + is->parse_thread.join(); + is->video_thread.join(); + + if(is->audioStream >= 0) + avcodec_close(is->audio_st->codec); + if(is->videoStream >= 0) + avcodec_close(is->video_st->codec); + + sws_freeContext(is->sws_context); + + AVIOContext *ioContext = is->format_ctx->pb; + avformat_close_input(&is->format_ctx); + av_free(ioContext); + } VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) : mState(NULL) @@ -919,22 +926,27 @@ public: mState->refresh = 0; mState->resourceName = resourceName; + mState->av_sync_type = DEFAULT_AV_SYNC_TYPE; + mState->format_ctx = avformat_alloc_context(); schedule_refresh(mState, 40); - mState->av_sync_type = DEFAULT_AV_SYNC_TYPE; + init_state(mState, resourceName); mState->parse_thread = boost::thread(decode_thread, mState); } void VideoPlayer::update () { - if (mState && mState->refresh) + if(mState) { - video_refresh_timer (mState); - mState->refresh--; + if(mState->quit) + close(); + else if(mState->refresh) + { + video_refresh_timer(mState); + mState->refresh--; + } } - if (mState && mState->quit) - close(); if (mState && mState->display_ready && !Ogre::TextureManager::getSingleton ().getByName ("VideoTexture").isNull ()) mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("VideoTexture"); @@ -945,8 +957,7 @@ public: void VideoPlayer::close() { mState->quit = 1; - - mState->parse_thread.join (); + deinit_state(mState); delete mState; mState = NULL; @@ -964,5 +975,4 @@ public: { return mState != NULL; } - } diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index eac906356..e97fa6e13 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -62,7 +62,7 @@ namespace MWRender audio_pkt_data(NULL), audio_pkt_size(0), audio_diff_cum(0), audio_diff_avg_coef(0), audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), frame_last_delay(0), video_clock(0), video_current_pts(0), video_current_pts_time(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), - pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), sws_context(NULL), display_ready(0) + pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) {} @@ -108,6 +108,7 @@ namespace MWRender MWBase::SoundPtr AudioTrack; + AVFormatContext* format_ctx; SwsContext* sws_context; VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; From 7e8b844b2e46ca1b4b58acb5aa65313792aaa403 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 03:05:37 -0800 Subject: [PATCH 089/916] Clean up some unused code --- apps/openmw/mwrender/videoplayer.cpp | 92 ++++++++++++---------------- 1 file changed, 39 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 0268539d5..d4fa7688f 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -393,20 +393,9 @@ public: return total; } - }; - /* - static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) { - SDL_Event event; - event.type = FF_REFRESH_EVENT; - event.user.data1 = opaque; - SDL_PushEvent(&event); - return 0; // 0 means stop timer - } - */ - void timer_callback (boost::system_time t, VideoState* is) { boost::this_thread::sleep (t); @@ -416,8 +405,6 @@ public: /* schedule a video refresh in 'delay' ms */ static void schedule_refresh(VideoState *is, int delay) { - //SDL_AddTimer(delay, sdl_refresh_timer_cb, is); - //is->refresh_queue.push_back (delay); boost::system_time t = boost::get_system_time() + boost::posix_time::milliseconds(delay); boost::thread (boost::bind(&timer_callback, t, is)).detach(); } @@ -460,10 +447,12 @@ public: VideoPicture *vp; double actual_delay, delay, sync_threshold, ref_clock, diff; - if(is->video_st) { - if(is->pictq_size == 0) { + if(is->video_st) + { + if(is->pictq_size == 0) schedule_refresh(is, 1); - } else { + else + { vp = &is->pictq[is->pictq_rindex]; is->video_current_pts = vp->pts; @@ -479,26 +468,28 @@ public: is->frame_last_pts = vp->pts; /* update delay to sync to audio if not master source */ - if(is->av_sync_type != AV_SYNC_VIDEO_MASTER) { + if(is->av_sync_type != AV_SYNC_VIDEO_MASTER) + { ref_clock = get_master_clock(is); diff = vp->pts - ref_clock; /* Skip or repeat the frame. Take delay into account FFPlay still doesn't "know if this is the best guess." */ sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; - if(fabs(diff) < AV_NOSYNC_THRESHOLD) { - if(diff <= -sync_threshold) { + if(fabs(diff) < AV_NOSYNC_THRESHOLD) + { + if(diff <= -sync_threshold) delay = 0; - } else if(diff >= sync_threshold) { + else if(diff >= sync_threshold) delay = 2 * delay; - } } } is->frame_timer += delay; /* computer the REAL delay */ actual_delay = is->frame_timer - (av_gettime() / 1000000.0); - if(actual_delay < 0.010) { + if(actual_delay < 0.010) + { /* Really it should skip the picture instead */ actual_delay = 0.010; } @@ -508,18 +499,16 @@ public: video_display(is); /* update queue for next picture! */ - if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) { + if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) is->pictq_rindex = 0; - } is->pictq_mutex.lock(); is->pictq_size--; is->pictq_cond.notify_one (); is->pictq_mutex.unlock (); } } - else { + else schedule_refresh(is, 100); - } } int queue_picture(VideoState *is, AVFrame *pFrame, double pts) @@ -529,9 +518,8 @@ public: /* wait until we have a new pic */ { boost::unique_lock lock(is->pictq_mutex); - while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->quit) { + while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->quit) is->pictq_cond.timed_wait(lock, boost::posix_time::milliseconds(1)); - } } if(is->quit) @@ -541,7 +529,8 @@ public: vp = &is->pictq[is->pictq_windex]; // Convert the image into YUV format that SDL uses - if(is->sws_context == NULL) { + if(is->sws_context == NULL) + { int w = is->video_st->codec->width; int h = is->video_st->codec->height; is->sws_context = sws_getContext(w, h, is->video_st->codec->pix_fmt, @@ -556,13 +545,11 @@ public: sws_scale(is->sws_context, pFrame->data, pFrame->linesize, 0, is->video_st->codec->height, &vp->data, is->rgbaFrame->linesize); - vp->pts = pts; // now we inform our display thread that we have a pic ready - if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) { + if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) is->pictq_windex = 0; - } is->pictq_mutex.lock(); is->pictq_size++; is->pictq_mutex.unlock(); @@ -574,10 +561,13 @@ public: { double frame_delay; - if(pts != 0) { + if(pts != 0) + { /* if we have pts, set video clock to it */ is->video_clock = pts; - } else { + } + else + { /* if we aren't given a pts, set it to the clock */ pts = is->video_clock; } @@ -619,11 +609,12 @@ public: pFrame = avcodec_alloc_frame(); is->rgbaFrame = avcodec_alloc_frame(); - avpicture_alloc ((AVPicture *)is->rgbaFrame, PIX_FMT_RGBA, is->video_st->codec->width, is->video_st->codec->height); + avpicture_alloc((AVPicture*)is->rgbaFrame, PIX_FMT_RGBA, is->video_st->codec->width, is->video_st->codec->height); - - for(;;) { - if(packet_queue_get(&is->videoq, packet, 1) < 0) { + for(;;) + { + if(packet_queue_get(&is->videoq, packet, 1) < 0) + { // means we quit getting packets break; } @@ -632,28 +623,24 @@ public: // Save global pts to be stored in pFrame global_video_pkt_pts = packet->pts; // Decode video frame - if (avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, - packet) < 0) - { + if (avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, packet) < 0) throw std::runtime_error("Error decoding video frame"); - } - if((uint64_t)packet->dts == AV_NOPTS_VALUE - && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) { + + if((uint64_t)packet->dts == AV_NOPTS_VALUE && + pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) pts = *(uint64_t *)pFrame->opaque; - } else if((uint64_t)packet->dts != AV_NOPTS_VALUE) { + else if((uint64_t)packet->dts != AV_NOPTS_VALUE) pts = packet->dts; - } else { + else pts = 0; - } pts *= av_q2d(is->video_st->time_base); - // Did we get a video frame? - if(frameFinished) { + if(frameFinished) + { pts = synchronize_video(is, pFrame, pts); - if(queue_picture(is, pFrame, pts) < 0) { + if(queue_picture(is, pFrame, pts) < 0) break; - } } av_free_packet(packet); } @@ -672,9 +659,8 @@ public: AVCodecContext *codecCtx; AVCodec *codec; - if(stream_index < 0 || stream_index >= static_cast(pFormatCtx->nb_streams)) { + if(stream_index < 0 || stream_index >= static_cast(pFormatCtx->nb_streams)) return -1; - } // Get a pointer to the codec context for the video stream codecCtx = pFormatCtx->streams[stream_index]->codec; From f7ff8b33741b4a7fbf30d1e89d19b24253ec4a53 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 03:13:44 -0800 Subject: [PATCH 090/916] A bit more cleanup --- apps/openmw/mwrender/videoplayer.cpp | 16 +++++++--------- apps/openmw/mwrender/videoplayer.hpp | 3 +-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index d4fa7688f..94f40e0e9 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -791,8 +791,11 @@ public: int audio_index = -1; unsigned int i; + is->av_sync_type = DEFAULT_AV_SYNC_TYPE; + is->format_ctx = avformat_alloc_context(); is->videoStream = -1; is->audioStream = -1; + is->refresh = 0; is->quit = 0; is->stream = Ogre::ResourceGroupManager::getSingleton ().openResource(resourceName); @@ -886,6 +889,9 @@ public: void VideoPlayer::playVideo (const std::string &resourceName) { + // Register all formats and codecs + av_register_all(); + if (mState) close(); @@ -907,17 +913,9 @@ public: mState = new VideoState; - // Register all formats and codecs - av_register_all(); - - mState->refresh = 0; - mState->resourceName = resourceName; - mState->av_sync_type = DEFAULT_AV_SYNC_TYPE; - mState->format_ctx = avformat_alloc_context(); + init_state(mState, resourceName); schedule_refresh(mState, 40); - - init_state(mState, resourceName); mState->parse_thread = boost::thread(decode_thread, mState); } diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index e97fa6e13..2ce58846f 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -121,8 +121,7 @@ namespace MWRender boost::thread parse_thread; boost::thread video_thread; - std::string resourceName; - int quit; + volatile int quit; int refresh; int display_ready; From 600494eed8ee8037f4a02f3ef11287347fecfe39 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 03:37:04 -0800 Subject: [PATCH 091/916] More cleanup of unused code --- apps/openmw/mwrender/videoplayer.cpp | 57 ++++++++++++---------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 94f40e0e9..df4d7c8ed 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -59,15 +59,9 @@ namespace MWRender } + void packet_queue_init(PacketQueue *q) + { memset(q, 0, sizeof(PacketQueue)); } - - /* Since we only have one decoding thread, the Big Struct - can be global in case we need it. */ - VideoState *global_video_state; - - void packet_queue_init(PacketQueue *q) { - memset(q, 0, sizeof(PacketQueue)); - } int packet_queue_put(PacketQueue *q, AVPacket *pkt) { AVPacketList *pkt1; @@ -92,7 +86,8 @@ namespace MWRender q->mutex.unlock (); return 0; } - static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) + + static int packet_queue_get(PacketQueue *q, AVPacket *pkt, VideoState *is, int block) { AVPacketList *pkt1; int ret; @@ -101,7 +96,7 @@ namespace MWRender for(;;) { - if(global_video_state->quit) + if(is->quit) { ret = -1; break; @@ -133,7 +128,8 @@ namespace MWRender return ret; } - void PacketQueue::flush() { + void PacketQueue::flush() + { AVPacketList *pkt, *pkt1; this->mutex.lock(); @@ -149,6 +145,7 @@ namespace MWRender this->mutex.unlock (); } + double get_audio_clock(VideoState *is) { return is->AudioTrack->getTimeOffset(); @@ -161,17 +158,19 @@ namespace MWRender delta = (av_gettime() - is->video_current_pts_time) / 1000000.0; return is->video_current_pts + delta; } - double get_external_clock(VideoState *is) { + + double get_external_clock(VideoState *is) + { return av_gettime() / 1000000.0; } - double get_master_clock(VideoState *is) { - if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) { + + double get_master_clock(VideoState *is) + { + if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) return get_video_clock(is); - } else if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) { + if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) return get_audio_clock(is); - } else { - return get_external_clock(is); - } + return get_external_clock(is); } class MovieAudioDecoder : public MWSound::Sound_Decoder @@ -296,7 +295,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder return -1; /* next packet */ - if(packet_queue_get(&is->audioq, pkt, 1) < 0) + if(packet_queue_get(&is->audioq, pkt, is, 1) < 0) return -1; is->audio_pkt_data = pkt->data; @@ -328,7 +327,7 @@ public: *type = MWSound::SampleType_Int16; else fail(std::string("Unsupported sample format: ")+ - av_get_sample_fmt_name(is->audio_st->codec->sample_fmt)); + av_get_sample_fmt_name(is->audio_st->codec->sample_fmt)); if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_MONO) *chans = MWSound::ChannelConfig_Mono; @@ -382,8 +381,8 @@ public: is->audio_buf_index = 0; } - size_t len1 = std::min(is->audio_buf_size - is->audio_buf_index, - len - total); + size_t len1 = std::min(is->audio_buf_size - is->audio_buf_index, + len - total); memcpy(stream, (uint8_t*)is->audio_buf + is->audio_buf_index, len1); total += len1; @@ -398,7 +397,7 @@ public: void timer_callback (boost::system_time t, VideoState* is) { - boost::this_thread::sleep (t); + boost::this_thread::sleep(t); is->refresh++; } @@ -406,7 +405,7 @@ public: static void schedule_refresh(VideoState *is, int delay) { boost::system_time t = boost::get_system_time() + boost::posix_time::milliseconds(delay); - boost::thread (boost::bind(&timer_callback, t, is)).detach(); + boost::thread(boost::bind(&timer_callback, t, is)).detach(); } void video_display(VideoState *is) @@ -613,7 +612,7 @@ public: for(;;) { - if(packet_queue_get(&is->videoq, packet, 1) < 0) + if(packet_queue_get(&is->videoq, packet, is, 1) < 0) { // means we quit getting packets break; @@ -721,10 +720,6 @@ public: return 0; } - int decode_interrupt_cb(void) { - return (global_video_state && global_video_state->quit); - } - int decode_thread(void *arg) { VideoState *is = (VideoState *)arg; @@ -806,10 +801,6 @@ public: if(!is->format_ctx->pb) throw std::runtime_error("Failed to allocate ioContext "); - global_video_state = is; - // will interrupt blocking functions if we quit! - //url_set_interrupt_cb(decode_interrupt_cb); - // Open video file /// \todo leak here, ffmpeg or valgrind bug ? if (avformat_open_input(&is->format_ctx, resourceName.c_str(), NULL, NULL)) From 1ea1407707c4651bcbd94eb2119e27bfde364cd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 04:10:19 -0800 Subject: [PATCH 092/916] Support quad, 5.1, and 7.1 with OpenAL and ffmpeg The other decoders don't guarantee any channel ordering, which makes them useless. --- apps/openmw/mwrender/videoplayer.cpp | 6 ++++++ apps/openmw/mwsound/ffmpeg_decoder.cpp | 6 ++++++ apps/openmw/mwsound/openal_output.cpp | 28 +++++++++++++++++++++++++ apps/openmw/mwsound/sound_decoder.hpp | 5 ++++- apps/openmw/mwsound/soundmanagerimp.cpp | 14 +++++++++---- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index df4d7c8ed..6e6db5f27 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -333,6 +333,12 @@ public: *chans = MWSound::ChannelConfig_Mono; else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_STEREO) *chans = MWSound::ChannelConfig_Stereo; + else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_QUAD) + *chans = MWSound::ChannelConfig_Quad; + else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_5POINT1) + *chans = MWSound::ChannelConfig_5point1; + else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_7POINT1) + *chans = MWSound::ChannelConfig_7point1; else if(is->audio_st->codec->channel_layout == 0) { /* Unknown channel layout. Try to guess. */ diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 6b3a7f9cd..9fee0d9b0 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -347,6 +347,12 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * *chans = ChannelConfig_Mono; else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO) *chans = ChannelConfig_Stereo; + else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_QUAD) + *chans = ChannelConfig_Quad; + else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1) + *chans = ChannelConfig_5point1; + else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1) + *chans = ChannelConfig_7point1; else if(stream->mCodecCtx->channel_layout == 0) { /* Unknown channel layout. Try to guess. */ diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index c7b16dd39..fd4fdaa9e 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -61,6 +61,34 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) if(fmtlist[i].chans == chans && fmtlist[i].type == type) return fmtlist[i].format; } + + if(alIsExtensionPresent("AL_EXT_MCFORMATS")) + { + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } mcfmtlist[] = { + { "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 }, + { "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 }, + { "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 }, + { "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 }, + { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 }, + { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 }, + }; + static const size_t mcfmtlistsize = sizeof(mcfmtlist)/sizeof(mcfmtlist[0]); + + for(size_t i = 0;i < mcfmtlistsize;i++) + { + if(mcfmtlist[i].chans == chans && mcfmtlist[i].type == type) + { + ALenum format = alGetEnumValue(mcfmtlist[i].name); + if(format != 0 && format != -1) + return format; + } + } + } + fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); return AL_NONE; } diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index d228a5e98..f78a1cd28 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -15,7 +15,10 @@ namespace MWSound enum ChannelConfig { ChannelConfig_Mono, - ChannelConfig_Stereo + ChannelConfig_Stereo, + ChannelConfig_Quad, + ChannelConfig_5point1, + ChannelConfig_7point1 }; const char *getChannelConfigName(ChannelConfig config); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 6bb3d59dd..efdb6f7ea 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -622,8 +622,11 @@ namespace MWSound { switch(config) { - case ChannelConfig_Mono: return "Mono"; - case ChannelConfig_Stereo: return "Stereo"; + case ChannelConfig_Mono: return "Mono"; + case ChannelConfig_Stereo: return "Stereo"; + case ChannelConfig_Quad: return "Quad"; + case ChannelConfig_5point1: return "5.1 Surround"; + case ChannelConfig_7point1: return "7.1 Surround"; } return "(unknown channel config)"; } @@ -632,8 +635,11 @@ namespace MWSound { switch(config) { - case ChannelConfig_Mono: frames *= 1; break; - case ChannelConfig_Stereo: frames *= 2; break; + case ChannelConfig_Mono: frames *= 1; break; + case ChannelConfig_Stereo: frames *= 2; break; + case ChannelConfig_Quad: frames *= 4; break; + case ChannelConfig_5point1: frames *= 6; break; + case ChannelConfig_7point1: frames *= 8; break; } switch(type) { From cab68df2574eec34254640770ca371450b341f42 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 04:25:41 -0800 Subject: [PATCH 093/916] Use the decoded frame pts when available --- apps/openmw/mwrender/videoplayer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 6e6db5f27..2d43e8ddc 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -631,11 +631,12 @@ public: if (avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, packet) < 0) throw std::runtime_error("Error decoding video frame"); - if((uint64_t)packet->dts == AV_NOPTS_VALUE && - pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) + if((uint64_t)pFrame->pts != AV_NOPTS_VALUE) + pts = pFrame->pts; + else if((uint64_t)packet->pts != AV_NOPTS_VALUE) + pts = packet->pts; + else if(pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) pts = *(uint64_t *)pFrame->opaque; - else if((uint64_t)packet->dts != AV_NOPTS_VALUE) - pts = packet->dts; else pts = 0; pts *= av_q2d(is->video_st->time_base); From 3d4c8c5444ae35b45537a1d877270befa62de4b9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Dec 2012 13:35:08 +0100 Subject: [PATCH 094/916] added dialogue sub view (editing of a single record; not functional yet); fixed a bug in Universal to string conversion --- apps/opencs/CMakeLists.txt | 2 ++ apps/opencs/model/world/columns.hpp | 18 ++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/model/world/universalid.cpp | 5 +++-- apps/opencs/model/world/universalid.hpp | 2 ++ apps/opencs/view/world/dialoguesubview.cpp | 14 +++++++++++++ apps/opencs/view/world/dialoguesubview.hpp | 24 ++++++++++++++++++++++ apps/opencs/view/world/subviews.cpp | 4 ++++ apps/opencs/view/world/table.cpp | 9 +++++++- apps/opencs/view/world/table.hpp | 2 ++ apps/opencs/view/world/tablesubview.cpp | 7 +++++++ apps/opencs/view/world/tablesubview.hpp | 8 +++++++- 12 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/view/world/dialoguesubview.cpp create mode 100644 apps/opencs/view/world/dialoguesubview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 554607c73..1cfb5d9a9 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -14,6 +14,7 @@ set (OPENCS_SRC view/doc/subview.cpp view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp + view/world/dialoguesubview.cpp view/tools/reportsubview.cpp view/tools/subviews.cpp ) @@ -34,6 +35,7 @@ set (OPENCS_HDR view/doc/subview.hpp view/doc/subviewfactoryimp.hpp view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp + view/world/dialoguesubview.hpp view/tools/reportsubview.hpp view/tools/subviews.hpp ) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 188d3a2ac..0d2d42158 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -67,6 +67,24 @@ namespace CSMWorld return true; } }; + + template + struct FixedRecordTypeColumn : public Column + { + int mType; + + FixedRecordTypeColumn (int type) : Column ("Type"), mType (type) {} + + virtual QVariant get (const Record& record) const + { + return mType; + } + + virtual bool isEditable() const + { + return false; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f350299ec..0da0cba83 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -14,6 +14,7 @@ CSMWorld::Data::Data() { mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); + mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); mGlobals.addColumn (new FloatValueColumn); mModels.insert (std::make_pair ( diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 81561bcf4..d8775643a 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -24,6 +24,7 @@ namespace static const TypeData sIdArg[] = { + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -208,8 +209,8 @@ std::string CSMWorld::UniversalId::toString() const switch (mArgumentType) { case ArgumentType_None: break; - case ArgumentType_Id: stream << ": " << mId; - case ArgumentType_Index: stream << ": " << mIndex; + case ArgumentType_Id: stream << ": " << mId; break; + case ArgumentType_Index: stream << ": " << mIndex; break; } return stream.str(); diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 8f43bf083..4a73feb12 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -36,6 +36,8 @@ namespace CSMWorld Type_Globals, + Type_Global, + Type_VerificationResults }; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp new file mode 100644 index 000000000..e2d16f1e3 --- /dev/null +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -0,0 +1,14 @@ + +#include "dialoguesubview.hpp" + +CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, + bool createAndDelete) +: SubView (id) +{ + +} + +void CSVWorld::DialogueSubView::setEditLock (bool locked) +{ + +} \ No newline at end of file diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp new file mode 100644 index 000000000..c57dab108 --- /dev/null +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -0,0 +1,24 @@ +#ifndef CSV_WORLD_DIALOGUESUBVIEW_H +#define CSV_WORLD_DIALOGUESUBVIEW_H + +#include "../doc/subview.hpp" + +namespace CSMDoc +{ + class Document; +} + +namespace CSVWorld +{ + class DialogueSubView : public CSVDoc::SubView + { + + public: + + DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); + + virtual void setEditLock (bool locked); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index fdc0cb31d..080a175ea 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -4,9 +4,13 @@ #include "../doc/subviewfactoryimp.hpp" #include "tablesubview.hpp" +#include "dialoguesubview.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { manager.add (CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreateFlag (true)); + + manager.add (CSMWorld::UniversalId::Type_Global, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 3a5ef7c34..6892c7f61 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -2,7 +2,7 @@ #include "table.hpp" #include -#include + #include #include #include @@ -129,6 +129,13 @@ void CSVWorld::Table::setEditLock (bool locked) mEditLock = locked; } +CSMWorld::UniversalId CSVWorld::Table::getUniversalId (int row) const +{ + return CSMWorld::UniversalId ( + static_cast (mProxyModel->data (mProxyModel->index (row, 2)).toInt()), + mProxyModel->data (mProxyModel->index (row, 0)).toString().toStdString()); +} + #include /// \todo remove void CSVWorld::Table::createRecord() { diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index b58ba8328..df0224583 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -50,6 +50,8 @@ namespace CSVWorld void setEditLock (bool locked); + CSMWorld::UniversalId getUniversalId (int row) const; + private slots: void createRecord(); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 4abd531d0..bb4bb76c6 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -10,9 +10,16 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D : SubView (id) { setWidget (mTable = new Table (id, document.getData(), document.getUndoStack(), createAndDelete)); + + connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (rowActivated (const QModelIndex&))); } void CSVWorld::TableSubView::setEditLock (bool locked) { mTable->setEditLock (locked); +} + +void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) +{ + focusId (mTable->getUniversalId (index.row())); } \ No newline at end of file diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index 9b0785c47..0e7b8aa30 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -3,7 +3,7 @@ #include "../doc/subview.hpp" -class QUndoStack; +class QModelIndex; namespace CSMDoc { @@ -16,6 +16,8 @@ namespace CSVWorld class TableSubView : public CSVDoc::SubView { + Q_OBJECT + Table *mTable; public: @@ -23,6 +25,10 @@ namespace CSVWorld TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); virtual void setEditLock (bool locked); + + private slots: + + void rowActivated (const QModelIndex& index); }; } From 640c218df392442b389b939e35a1ee7259c71caf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Dec 2012 13:52:26 +0100 Subject: [PATCH 095/916] made record state uneditable again --- apps/opencs/model/world/columns.hpp | 5 +++++ apps/opencs/model/world/idcollection.hpp | 19 +++++++++++++++++++ apps/opencs/model/world/idtable.cpp | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 0d2d42158..00c688484 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -66,6 +66,11 @@ namespace CSMWorld { return true; } + + virtual bool isUserEditable() const + { + return false; + } }; template diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 50afa715e..529e474d5 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -32,8 +32,17 @@ namespace CSMWorld } virtual bool isEditable() const = 0; + + virtual bool isUserEditable() const; + ///< Can this column be edited directly by the user? }; + template + bool Column::isUserEditable() const + { + return isEditable(); + } + class IdCollectionBase { // not implemented @@ -62,6 +71,8 @@ namespace CSMWorld virtual bool isEditable (int column) const = 0; + virtual bool isUserEditable (int column) const = 0; + virtual void merge() = 0; ///< Merge modified into base. @@ -129,6 +140,8 @@ namespace CSMWorld virtual bool isEditable (int column) const; + virtual bool isUserEditable (int column) const; + virtual void merge(); ///< Merge modified into base. @@ -250,6 +263,12 @@ namespace CSMWorld return mColumns.at (column)->isEditable(); } + template + bool IdCollection::isUserEditable (int column) const + { + return mColumns.at (column)->isUserEditable(); + } + template void IdCollection::addColumn (Column *column) { diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 3fe1fadfe..3ec2f3d17 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -70,7 +70,7 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - if (mIdCollection->isEditable (index.column())) + if (mIdCollection->isUserEditable (index.column())) flags |= Qt::ItemIsEditable; return flags; From 0a5ab977b75ddd246b8fd37d8a8a0b545d114b03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 05:04:53 -0800 Subject: [PATCH 096/916] Use the decoder's sample offset for calculating the stream offset --- apps/openmw/mwrender/videoplayer.cpp | 5 +++++ apps/openmw/mwsound/audiere_decoder.cpp | 5 +++++ apps/openmw/mwsound/audiere_decoder.hpp | 1 + apps/openmw/mwsound/ffmpeg_decoder.cpp | 14 ++++++++++++-- apps/openmw/mwsound/ffmpeg_decoder.hpp | 2 ++ apps/openmw/mwsound/mpgsnd_decoder.cpp | 5 +++++ apps/openmw/mwsound/mpgsnd_decoder.hpp | 1 + apps/openmw/mwsound/openal_output.cpp | 11 +++-------- apps/openmw/mwsound/sound_decoder.hpp | 1 + 9 files changed, 35 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 2d43e8ddc..bd29c69bf 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -398,6 +398,11 @@ public: return total; } + + size_t getSampleOffset() + { + return (size_t)(is->audio_clock*is->audio_st->codec->sample_rate); + } }; diff --git a/apps/openmw/mwsound/audiere_decoder.cpp b/apps/openmw/mwsound/audiere_decoder.cpp index c9b3d11d1..788d5ae40 100644 --- a/apps/openmw/mwsound/audiere_decoder.cpp +++ b/apps/openmw/mwsound/audiere_decoder.cpp @@ -117,6 +117,11 @@ void Audiere_Decoder::rewind() mSoundSource->reset(); } +size_t Audiere_Decoder::getSampleOffset() +{ + return 0; +} + Audiere_Decoder::Audiere_Decoder() { } diff --git a/apps/openmw/mwsound/audiere_decoder.hpp b/apps/openmw/mwsound/audiere_decoder.hpp index 1e1528880..8623a3f2c 100644 --- a/apps/openmw/mwsound/audiere_decoder.hpp +++ b/apps/openmw/mwsound/audiere_decoder.hpp @@ -25,6 +25,7 @@ namespace MWSound virtual size_t read(char *buffer, size_t bytes); virtual void rewind(); + virtual size_t getSampleOffset(); Audiere_Decoder& operator=(const Audiere_Decoder &rhs); Audiere_Decoder(const Audiere_Decoder &rhs); diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 9fee0d9b0..6e60a7b9e 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -383,7 +383,11 @@ size_t FFmpeg_Decoder::read(char *buffer, size_t bytes) if(mStreams.empty()) fail("No audio streams"); - return mStreams.front()->readAVAudioData(buffer, bytes); + MyStream *stream = mStreams.front(); + size_t got = stream->readAVAudioData(buffer, bytes); + mSamplesRead += got / av_samples_get_buffer_size(NULL, stream->mCodecCtx->channels, 1, + stream->mCodecCtx->sample_fmt, 1); + return got; } void FFmpeg_Decoder::readAll(std::vector &output) @@ -402,9 +406,15 @@ void FFmpeg_Decoder::rewind() { av_seek_frame(mFormatCtx, -1, 0, 0); std::for_each(mStreams.begin(), mStreams.end(), std::mem_fun(&MyStream::clearPackets)); + mSamplesRead = 0; } -FFmpeg_Decoder::FFmpeg_Decoder() : mFormatCtx(NULL) +size_t FFmpeg_Decoder::getSampleOffset() +{ + return mSamplesRead; +} + +FFmpeg_Decoder::FFmpeg_Decoder() : mFormatCtx(NULL), mSamplesRead(0) { static bool done_init = false; diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 88115ce3f..ff63edf07 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -25,6 +25,7 @@ namespace MWSound struct MyStream; std::vector mStreams; + size_t mSamplesRead; bool getNextPacket(int streamidx); @@ -42,6 +43,7 @@ namespace MWSound virtual size_t read(char *buffer, size_t bytes); virtual void readAll(std::vector &output); virtual void rewind(); + virtual size_t getSampleOffset(); FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs); FFmpeg_Decoder(const FFmpeg_Decoder &rhs); diff --git a/apps/openmw/mwsound/mpgsnd_decoder.cpp b/apps/openmw/mwsound/mpgsnd_decoder.cpp index 4ec11b349..fb187f844 100644 --- a/apps/openmw/mwsound/mpgsnd_decoder.cpp +++ b/apps/openmw/mwsound/mpgsnd_decoder.cpp @@ -218,6 +218,11 @@ void MpgSnd_Decoder::rewind() } } +size_t MpgSnd_Decoder::getSampleOffset() +{ + return 0; +} + MpgSnd_Decoder::MpgSnd_Decoder() : mSndInfo() , mSndFile(NULL) diff --git a/apps/openmw/mwsound/mpgsnd_decoder.hpp b/apps/openmw/mwsound/mpgsnd_decoder.hpp index 09082c2f4..52c37bb87 100644 --- a/apps/openmw/mwsound/mpgsnd_decoder.hpp +++ b/apps/openmw/mwsound/mpgsnd_decoder.hpp @@ -39,6 +39,7 @@ namespace MWSound virtual size_t read(char *buffer, size_t bytes); virtual void readAll(std::vector &output); virtual void rewind(); + virtual size_t getSampleOffset(); MpgSnd_Decoder& operator=(const MpgSnd_Decoder &rhs); MpgSnd_Decoder(const MpgSnd_Decoder &rhs); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index fd4fdaa9e..672e52b56 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -122,7 +122,6 @@ class OpenAL_SoundStream : public Sound ALsizei mSampleRate; ALuint mBufferSize; - ALuint mSamplesTotal; ALuint mSamplesQueued; DecoderPtr mDecoder; @@ -215,8 +214,7 @@ private: OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder) - : mOutput(output), mSource(src), mSamplesTotal(0), mSamplesQueued(0), - mDecoder(decoder), mIsFinished(true) + : mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true) { throwALerror(); @@ -286,7 +284,6 @@ void OpenAL_SoundStream::stop() mSamplesQueued = 0; mDecoder->rewind(); - mSamplesTotal = 0; } bool OpenAL_SoundStream::isPlaying() @@ -311,9 +308,9 @@ double OpenAL_SoundStream::getTimeOffset() alGetSourcef(mSource, AL_SEC_OFFSET, &offset); alGetSourcei(mSource, AL_SOURCE_STATE, &state); if(state == AL_PLAYING || state == AL_PAUSED) - t = (double)(mSamplesTotal - mSamplesQueued)/(double)mSampleRate + offset; + t = (double)(mDecoder->getSampleOffset() - mSamplesQueued)/(double)mSampleRate + offset; else - t = (double)mSamplesTotal / (double)mSampleRate; + t = (double)mDecoder->getSampleOffset() / (double)mSampleRate; mOutput.mStreamThread->mMutex.unlock(); throwALerror(); @@ -388,13 +385,11 @@ bool OpenAL_SoundStream::process() mSamplesQueued -= samples_unqueued; mSamplesQueued += samples_queued; - mSamplesTotal += samples_queued; mIsFinished = finished; } catch(std::exception &e) { std::cout<< "Error updating stream \""<getName()<<"\"" < &output); virtual void rewind() = 0; + virtual size_t getSampleOffset() = 0; Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) { } From faa5ef087463bd25e7e7bee47b6fcbd4f3b2de57 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Dec 2012 14:53:16 +0100 Subject: [PATCH 097/916] rewrote column class --- apps/opencs/model/world/idcollection.cpp | 11 ++++ apps/opencs/model/world/idcollection.hpp | 75 +++++++++++------------- apps/opencs/model/world/idtable.cpp | 17 +++--- 3 files changed, 56 insertions(+), 47 deletions(-) diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp index fc4bb1ef6..c6469ea98 100644 --- a/apps/opencs/model/world/idcollection.cpp +++ b/apps/opencs/model/world/idcollection.cpp @@ -1,6 +1,17 @@ #include "idcollection.hpp" +CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags) +: mTitle (title), mFlags (flags) +{} + +CSMWorld::ColumnBase::~ColumnBase() {} + +bool CSMWorld::ColumnBase::isUserEditable() const +{ + return isEditable(); +} + CSMWorld::IdCollectionBase::IdCollectionBase() {} CSMWorld::IdCollectionBase::~IdCollectionBase() {} \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 529e474d5..5d6f52aa0 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -15,21 +15,25 @@ namespace CSMWorld { - template - struct Column + struct ColumnBase { - std::string mTitle; - - Column (const std::string& title) : mTitle (title) {} - - virtual ~Column() {} - - virtual QVariant get (const Record& record) const = 0; - - virtual void set (Record& record, const QVariant& data) + enum Roles { - throw std::logic_error ("Column " + mTitle + " is not editable"); - } + Role_Flags = Qt::UserRole + }; + + enum Flags + { + Flag_Table = 1, // column should be displayed in table view + Flag_Dialogue = 2 // column should be displayed in dialogue view + }; + + std::string mTitle; + int mFlags; + + ColumnBase (const std::string& title, int flag); + + virtual ~ColumnBase(); virtual bool isEditable() const = 0; @@ -38,10 +42,21 @@ namespace CSMWorld }; template - bool Column::isUserEditable() const + struct Column : public ColumnBase { - return isEditable(); - } + std::string mTitle; + int mFlags; + + Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue) + : ColumnBase (title, flags) {} + + virtual QVariant get (const Record& record) const = 0; + + virtual void set (Record& record, const QVariant& data) + { + throw std::logic_error ("Column " + mTitle + " is not editable"); + } + }; class IdCollectionBase { @@ -63,16 +78,12 @@ namespace CSMWorld virtual int getColumns() const = 0; - virtual std::string getTitle (int column) const = 0; + virtual const ColumnBase& getColumn (int column) const = 0; virtual QVariant getData (int index, int column) const = 0; virtual void setData (int index, int column, const QVariant& data) = 0; - virtual bool isEditable (int column) const = 0; - - virtual bool isUserEditable (int column) const = 0; - virtual void merge() = 0; ///< Merge modified into base. @@ -136,11 +147,7 @@ namespace CSMWorld virtual void setData (int index, int column, const QVariant& data); - virtual std::string getTitle (int column) const; - - virtual bool isEditable (int column) const; - - virtual bool isUserEditable (int column) const; + virtual const ColumnBase& getColumn (int column) const; virtual void merge(); ///< Merge modified into base. @@ -252,21 +259,9 @@ namespace CSMWorld } template - std::string IdCollection::getTitle (int column) const + const ColumnBase& IdCollection::getColumn (int column) const { - return mColumns.at (column)->mTitle; - } - - template - bool IdCollection::isEditable (int column) const - { - return mColumns.at (column)->isEditable(); - } - - template - bool IdCollection::isUserEditable (int column) const - { - return mColumns.at (column)->isUserEditable(); + return *mColumns.at (column); } template diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 3ec2f3d17..2815e318c 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -34,7 +34,7 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const if (role!=Qt::DisplayRole && role!=Qt::EditRole) return QVariant(); - if (role==Qt::EditRole && !mIdCollection->isEditable (index.column())) + if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) return QVariant(); return mIdCollection->getData (index.row(), index.column()); @@ -42,18 +42,21 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const { - if (role!=Qt::DisplayRole) - return QVariant(); - if (orientation==Qt::Vertical) return QVariant(); - return tr (mIdCollection->getTitle (section).c_str()); + if (role==Qt::DisplayRole) + return tr (mIdCollection->getColumn (section).mTitle.c_str()); + + if (role==ColumnBase::Role_Flags) + return mIdCollection->getColumn (section).mFlags; + + return QVariant(); } bool CSMWorld::IdTable::setData ( const QModelIndex &index, const QVariant &value, int role) { - if (mIdCollection->isEditable (index.column()) && role==Qt::EditRole) + if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole) { mIdCollection->setData (index.row(), index.column(), value); @@ -70,7 +73,7 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - if (mIdCollection->isUserEditable (index.column())) + if (mIdCollection->getColumn (index.column()).isUserEditable()) flags |= Qt::ItemIsEditable; return flags; From f95e72166c20cd6e64cebc5bb46b937e6ca62ccc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 13 Dec 2012 15:03:35 +0100 Subject: [PATCH 098/916] hide type column in non-mixed type tables --- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/view/world/table.cpp | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 00c688484..f58d77c90 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -78,7 +78,7 @@ namespace CSMWorld { int mType; - FixedRecordTypeColumn (int type) : Column ("Type"), mType (type) {} + FixedRecordTypeColumn (int type) : Column ("Type", 0), mType (type) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 6892c7f61..0721ead2c 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -84,15 +84,6 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q { mModel = &dynamic_cast (*data.getTableModel (id)); - int columns = mModel->columnCount(); - - for (int i=0; isetSourceModel (mModel); @@ -103,6 +94,22 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionMode (QAbstractItemView::ExtendedSelection); + int columns = mModel->columnCount(); + + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + + if (flags & CSMWorld::ColumnBase::Flag_Table) + { + CommandDelegate *delegate = new CommandDelegate (undoStack, this); + mDelegates.push_back (delegate); + setItemDelegateForColumn (i, delegate); + } + else + hideColumn (i); + } + /// \todo make initial layout fill the whole width of the table if (createAndDelete) From 43481ad117da4da25aedd4aad6ff379d1ff74887 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 06:11:32 -0800 Subject: [PATCH 099/916] Use the external clock by default --- apps/openmw/mwrender/videoplayer.cpp | 3 ++- apps/openmw/mwrender/videoplayer.hpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index bd29c69bf..a5743356a 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -609,7 +609,8 @@ public: avcodec_default_release_buffer(c, pic); } - int video_thread(void *arg) { + int video_thread(void *arg) + { VideoState *is = (VideoState *)arg; AVPacket pkt1, *packet = &pkt1; int frameFinished; diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 2ce58846f..ace36efb9 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -28,7 +28,7 @@ extern "C" #define SAMPLE_CORRECTION_PERCENT_MAX 10 #define AUDIO_DIFF_AVG_NB 20 #define VIDEO_PICTURE_QUEUE_SIZE 1 -#define DEFAULT_AV_SYNC_TYPE AV_SYNC_VIDEO_MASTER +#define DEFAULT_AV_SYNC_TYPE AV_SYNC_EXTERNAL_MASTER namespace MWRender From 9d6f6568224578614bb3e118583786e5f2032d05 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 14 Dec 2012 00:10:54 +0100 Subject: [PATCH 100/916] fixed ogre resource functions --- apps/openmw/mwrender/videoplayer.cpp | 55 ++++++++++------------------ 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index a5743356a..21805a792 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -11,54 +11,37 @@ namespace MWRender { - int OgreResource_Read(void *opaque, uint8_t *buf, int buf_size) + int OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = static_cast(opaque)->stream; - - int num_read = stream->size() - stream->tell(); - - if (num_read > buf_size) - num_read = buf_size; - - stream->read(buf, num_read); - return num_read; + Ogre::DataStreamPtr stream = static_cast(user_data)->stream; + return stream->read(buf, buf_size); } - int OgreResource_Write(void *opaque, uint8_t *buf, int buf_size) + int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) { - Ogre::DataStreamPtr stream = static_cast(opaque)->stream; - - int num_write = stream->size() - stream->tell(); - - if (num_write > buf_size) - num_write = buf_size; - - stream->write (buf, num_write); - return num_write; + Ogre::DataStreamPtr stream = static_cast(user_data)->stream; + return stream->write(buf, buf_size); } - int64_t OgreResource_Seek(void *opaque, int64_t offset, int whence) + int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence) { - Ogre::DataStreamPtr stream = static_cast(opaque)->stream; + Ogre::DataStreamPtr stream = static_cast(user_data)->stream; - switch (whence) - { - case SEEK_SET: - stream->seek(offset); - case SEEK_CUR: - stream->seek(stream->tell() + offset); - case SEEK_END: - stream->seek(stream->size() + offset); - case AVSEEK_SIZE: - return stream->size(); - default: - return -1; - } + whence &= ~AVSEEK_FORCE; + if(whence == AVSEEK_SIZE) + return stream->size(); + if(whence == SEEK_SET) + stream->seek(offset); + else if(whence == SEEK_CUR) + stream->seek(stream->tell()+offset); + else if(whence == SEEK_END) + stream->seek(stream->size()+offset); + else + return -1; return stream->tell(); } - void packet_queue_init(PacketQueue *q) { memset(q, 0, sizeof(PacketQueue)); } From 27cd9ff7322269c7d0e8c91ac9f6a1ddc300cf2d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 14 Dec 2012 01:03:49 +0100 Subject: [PATCH 101/916] Revert "Use the decoded frame pts when available" This reverts commit cab68df2574eec34254640770ca371450b341f42. --- apps/openmw/mwrender/videoplayer.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 21805a792..7e2be7e10 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -620,12 +620,11 @@ public: if (avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, packet) < 0) throw std::runtime_error("Error decoding video frame"); - if((uint64_t)pFrame->pts != AV_NOPTS_VALUE) - pts = pFrame->pts; - else if((uint64_t)packet->pts != AV_NOPTS_VALUE) - pts = packet->pts; - else if(pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) + if((uint64_t)packet->dts == AV_NOPTS_VALUE && + pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) pts = *(uint64_t *)pFrame->opaque; + else if((uint64_t)packet->dts != AV_NOPTS_VALUE) + pts = packet->dts; else pts = 0; pts *= av_q2d(is->video_st->time_base); From 82564e07c7edefe5ac8ab0b8e23db55ce39b0dd3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 14 Dec 2012 01:44:00 +0100 Subject: [PATCH 102/916] fix crash when video file doesn't exist --- apps/openmw/mwrender/videoplayer.cpp | 115 ++++++++++++++++----------- 1 file changed, 70 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 7e2be7e10..299b34c32 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -777,49 +777,70 @@ public: void init_state(VideoState *is, const std::string& resourceName) { - int video_index = -1; - int audio_index = -1; - unsigned int i; - - is->av_sync_type = DEFAULT_AV_SYNC_TYPE; - is->format_ctx = avformat_alloc_context(); - is->videoStream = -1; - is->audioStream = -1; - is->refresh = 0; - is->quit = 0; - - is->stream = Ogre::ResourceGroupManager::getSingleton ().openResource(resourceName); - if(is->stream.isNull()) - throw std::runtime_error("Failed to open video resource"); - - is->format_ctx->pb = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); - if(!is->format_ctx->pb) - throw std::runtime_error("Failed to allocate ioContext "); - - // Open video file - /// \todo leak here, ffmpeg or valgrind bug ? - if (avformat_open_input(&is->format_ctx, resourceName.c_str(), NULL, NULL)) - throw std::runtime_error("Failed to open video input"); - - // Retrieve stream information - if(avformat_find_stream_info(is->format_ctx, NULL) < 0) - throw std::runtime_error("Failed to retrieve stream information"); - - // Dump information about file onto standard error - av_dump_format(is->format_ctx, 0, resourceName.c_str(), 0); - - for(i = 0;i < is->format_ctx->nb_streams;i++) + try { - if(is->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) - video_index = i; - if(is->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) - audio_index = i; - } + int video_index = -1; + int audio_index = -1; + unsigned int i; - if(audio_index >= 0) - stream_component_open(is, audio_index, is->format_ctx); - if(video_index >= 0) - stream_component_open(is, video_index, is->format_ctx); + is->av_sync_type = DEFAULT_AV_SYNC_TYPE; + is->videoStream = -1; + is->audioStream = -1; + is->refresh = 0; + is->quit = 0; + + is->stream = Ogre::ResourceGroupManager::getSingleton ().openResource(resourceName); + if(is->stream.isNull()) + throw std::runtime_error("Failed to open video resource"); + + is->format_ctx = avformat_alloc_context(); + + is->format_ctx->pb = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if(!is->format_ctx->pb) + { + avformat_free_context(is->format_ctx); + throw std::runtime_error("Failed to allocate ioContext "); + } + + // Open video file + /// \todo leak here, ffmpeg or valgrind bug ? + if (avformat_open_input(&is->format_ctx, resourceName.c_str(), NULL, NULL)) + { + // "Note that a user-supplied AVFormatContext will be freed on failure." + is->format_ctx = NULL; + throw std::runtime_error("Failed to open video input"); + } + + // Retrieve stream information + if(avformat_find_stream_info(is->format_ctx, NULL) < 0) + throw std::runtime_error("Failed to retrieve stream information"); + + // Dump information about file onto standard error + av_dump_format(is->format_ctx, 0, resourceName.c_str(), 0); + + for(i = 0;i < is->format_ctx->nb_streams;i++) + { + if(is->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) + video_index = i; + if(is->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) + audio_index = i; + } + + if(audio_index >= 0) + stream_component_open(is, audio_index, is->format_ctx); + if(video_index >= 0) + stream_component_open(is, video_index, is->format_ctx); + } + catch (std::runtime_error& e) + { + is->quit = 1; + throw; + } + catch (Ogre::Exception& e) + { + is->quit = 1; + throw; + } } void deinit_state(VideoState *is) @@ -835,11 +856,15 @@ public: if(is->videoStream >= 0) avcodec_close(is->video_st->codec); - sws_freeContext(is->sws_context); + if (is->sws_context) + sws_freeContext(is->sws_context); - AVIOContext *ioContext = is->format_ctx->pb; - avformat_close_input(&is->format_ctx); - av_free(ioContext); + if (is->format_ctx) + { + AVIOContext *ioContext = is->format_ctx->pb; + avformat_close_input(&is->format_ctx); + av_free(ioContext); + } } VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) From 606fb982a821d1805d5b51a02a9e84e6b857f033 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 17:53:22 -0800 Subject: [PATCH 103/916] Update to use avcodec_decode_audio4 --- apps/openmw/mwrender/videoplayer.cpp | 82 +++++++++++++++++----------- apps/openmw/mwrender/videoplayer.hpp | 15 ++--- 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 7e2be7e10..6acbe8b79 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -165,6 +165,10 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder VideoState *is; + AVFrame *mFrame; + size_t mFramePos; + size_t mFrameSize; + /* Add or subtract samples to get a better sync, return new * audio buffer size */ int synchronize_audio(uint8_t *samples, int samples_size, double pts) @@ -210,16 +214,19 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder { uint8_t *samples_end, *q; int nb; + /* add samples by copying final sample*/ nb = (samples_size - wanted_size); samples_end = samples + samples_size - n; q = samples_end + n; + while(nb > 0) { memcpy(q, samples_end, n); q += n; nb -= n; } + samples_size = wanted_size; } } @@ -235,38 +242,47 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder return samples_size; } - int audio_decode_frame(uint8_t *audio_buf, int buf_size, double *pts_ptr) + int audio_decode_frame(AVFrame *frame, double *pts_ptr) { AVPacket *pkt = &is->audio_pkt; - int len1, data_size, n; - double pts; + int len1, data_size; for(;;) { - while(is->audio_pkt_size > 0) + while(pkt->size > 0) { - data_size = buf_size; + int got_frame; - len1 = avcodec_decode_audio3(is->audio_st->codec, - (int16_t*)audio_buf, &data_size, pkt); - if(len1 < 0) + len1 = avcodec_decode_audio4(is->audio_st->codec, frame, &got_frame, pkt); + if(len1 < 0 || len1 > pkt->size) { - /* if error, skip frame */ - is->audio_pkt_size = 0; + /* if error, skip packet */ break; } - is->audio_pkt_data += len1; - is->audio_pkt_size -= len1; + + if(len1 <= pkt->size) + { + /* Move the unread data to the front and clear the end bits */ + int remaining = pkt->size - len1; + memmove(pkt->data, &pkt->data[len1], remaining); + memset(&pkt->data[remaining], 0, pkt->size - remaining); + pkt->size -= len1; + } + if(!got_frame) + continue; + + int smp_size = av_samples_get_buffer_size(NULL, is->audio_st->codec->channels, 1, + is->audio_st->codec->sample_fmt, 1); + data_size = frame->nb_samples * smp_size; if(data_size <= 0) { /* No data yet, get more frames */ continue; } - pts = is->audio_clock; - *pts_ptr = pts; - n = 2 * is->audio_st->codec->channels; - is->audio_clock += (double)data_size / - (double)(n * is->audio_st->codec->sample_rate); + + *pts_ptr = is->audio_clock; + is->audio_clock += (double)(data_size/smp_size) / + (double)is->audio_st->codec->sample_rate; /* We have data, return it and come back for more later */ return data_size; @@ -281,8 +297,6 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder if(packet_queue_get(&is->audioq, pkt, is, 1) < 0) return -1; - is->audio_pkt_data = pkt->data; - is->audio_pkt_size = pkt->size; /* if update, update the audio clock w/pts */ if((uint64_t)pkt->pts != AV_NOPTS_VALUE) is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; @@ -300,7 +314,16 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder void rewind() { } public: - MovieAudioDecoder(VideoState *_is) : is(_is) { } + MovieAudioDecoder(VideoState *_is) + : is(_is) + , mFrame(avcodec_alloc_frame()) + , mFramePos(0) + , mFrameSize(0) + { } + virtual ~MovieAudioDecoder() + { + av_freep(&mFrame); + } void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) { @@ -353,30 +376,29 @@ public: while(total < len) { - if(is->audio_buf_index >= is->audio_buf_size) + if(mFramePos >= mFrameSize) { int audio_size; double pts; + /* We have already sent all our data; get more */ - audio_size = audio_decode_frame(is->audio_buf, sizeof(is->audio_buf), &pts); + audio_size = audio_decode_frame(mFrame, &pts); if(audio_size < 0) { /* If error, we're done */ break; } - audio_size = synchronize_audio(is->audio_buf, audio_size, pts); - is->audio_buf_size = audio_size; - is->audio_buf_index = 0; + mFrameSize = synchronize_audio(mFrame->data[0], audio_size, pts); + mFramePos = 0; } - size_t len1 = std::min(is->audio_buf_size - is->audio_buf_index, - len - total); - memcpy(stream, (uint8_t*)is->audio_buf + is->audio_buf_index, len1); + size_t len1 = std::min(len - total, mFrameSize-mFramePos); + memcpy(stream, mFrame->data[0]+mFramePos, len1); total += len1; stream += len1; - is->audio_buf_index += len1; + mFramePos += len1; } return total; @@ -670,8 +692,6 @@ public: case AVMEDIA_TYPE_AUDIO: is->audioStream = stream_index; is->audio_st = pFormatCtx->streams[stream_index]; - is->audio_buf_size = 0; - is->audio_buf_index = 0; /* averaging filter for audio sync */ is->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index ace36efb9..689b3ad36 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -58,11 +58,11 @@ namespace MWRender struct VideoState { VideoState () : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock(0), - external_clock_time(0), audio_clock(0), audio_st(NULL), audio_buf_size(0), - audio_pkt_data(NULL), audio_pkt_size(0), audio_diff_cum(0), audio_diff_avg_coef(0), - audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), frame_last_delay(0), - video_clock(0), video_current_pts(0), video_current_pts_time(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), - pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) + external_clock_time(0), audio_clock(0), audio_st(NULL), audio_diff_cum(0), + audio_diff_avg_coef(0), audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), + frame_last_pts(0), frame_last_delay(0), video_clock(0), video_current_pts(0), + video_current_pts_time(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), + pictq_windex(0), quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) {} @@ -84,12 +84,7 @@ namespace MWRender double audio_clock; AVStream *audio_st; PacketQueue audioq; - DECLARE_ALIGNED(16, uint8_t, audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]); - unsigned int audio_buf_size; - unsigned int audio_buf_index; AVPacket audio_pkt; - uint8_t *audio_pkt_data; - int audio_pkt_size; double audio_diff_cum; /* used for AV difference average computation */ double audio_diff_avg_coef; double audio_diff_threshold; From 6cedd64509d0b59a4714f853408b7bcf22b582a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 18:05:27 -0800 Subject: [PATCH 104/916] Fix audio sync correction sizes --- apps/openmw/mwrender/videoplayer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index c2781935c..38b519b21 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -197,8 +197,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder if(fabs(avg_diff) >= is->audio_diff_threshold) { wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); - min_size = samples_size * ((100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100); - max_size = samples_size * ((100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100); + min_size = samples_size/n * (100-SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; + max_size = samples_size/n * (100+SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; if(wanted_size < min_size) wanted_size = min_size; From f555dc60eb05cbf0716e3785185c4da69b22a9ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 18:12:17 -0800 Subject: [PATCH 105/916] Reduce some indentation --- apps/openmw/mwrender/videoplayer.cpp | 117 ++++++++++++++------------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 38b519b21..a6e033216 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -462,68 +462,69 @@ public: VideoPicture *vp; double actual_delay, delay, sync_threshold, ref_clock, diff; - if(is->video_st) + if(!is->video_st) { - if(is->pictq_size == 0) - schedule_refresh(is, 1); - else + schedule_refresh(is, 100); + return; + } + if(is->pictq_size == 0) + { + schedule_refresh(is, 1); + return; + } + + vp = &is->pictq[is->pictq_rindex]; + + is->video_current_pts = vp->pts; + is->video_current_pts_time = av_gettime(); + + delay = vp->pts - is->frame_last_pts; /* the pts from last time */ + if(delay <= 0 || delay >= 1.0) { + /* if incorrect delay, use previous one */ + delay = is->frame_last_delay; + } + /* save for next time */ + is->frame_last_delay = delay; + is->frame_last_pts = vp->pts; + + /* update delay to sync to audio if not master source */ + if(is->av_sync_type != AV_SYNC_VIDEO_MASTER) + { + ref_clock = get_master_clock(is); + diff = vp->pts - ref_clock; + + /* Skip or repeat the frame. Take delay into account + FFPlay still doesn't "know if this is the best guess." */ + sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; + if(fabs(diff) < AV_NOSYNC_THRESHOLD) { - vp = &is->pictq[is->pictq_rindex]; - - is->video_current_pts = vp->pts; - is->video_current_pts_time = av_gettime(); - - delay = vp->pts - is->frame_last_pts; /* the pts from last time */ - if(delay <= 0 || delay >= 1.0) { - /* if incorrect delay, use previous one */ - delay = is->frame_last_delay; - } - /* save for next time */ - is->frame_last_delay = delay; - is->frame_last_pts = vp->pts; - - /* update delay to sync to audio if not master source */ - if(is->av_sync_type != AV_SYNC_VIDEO_MASTER) - { - ref_clock = get_master_clock(is); - diff = vp->pts - ref_clock; - - /* Skip or repeat the frame. Take delay into account - FFPlay still doesn't "know if this is the best guess." */ - sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; - if(fabs(diff) < AV_NOSYNC_THRESHOLD) - { - if(diff <= -sync_threshold) - delay = 0; - else if(diff >= sync_threshold) - delay = 2 * delay; - } - } - - is->frame_timer += delay; - /* computer the REAL delay */ - actual_delay = is->frame_timer - (av_gettime() / 1000000.0); - if(actual_delay < 0.010) - { - /* Really it should skip the picture instead */ - actual_delay = 0.010; - } - schedule_refresh(is, (int)(actual_delay * 1000 + 0.5)); - - /* show the picture! */ - video_display(is); - - /* update queue for next picture! */ - if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) - is->pictq_rindex = 0; - is->pictq_mutex.lock(); - is->pictq_size--; - is->pictq_cond.notify_one (); - is->pictq_mutex.unlock (); + if(diff <= -sync_threshold) + delay = 0; + else if(diff >= sync_threshold) + delay = 2 * delay; } } - else - schedule_refresh(is, 100); + + is->frame_timer += delay; + /* computer the REAL delay */ + actual_delay = is->frame_timer - (av_gettime() / 1000000.0); + if(actual_delay < 0.010) + { + /* Really it should skip the picture instead */ + actual_delay = 0.010; + } + schedule_refresh(is, (int)(actual_delay * 1000 + 0.5)); + + /* show the picture! */ + video_display(is); + + /* update queue for next picture! */ + if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) + is->pictq_rindex = 0; + is->pictq_mutex.lock(); + is->pictq_size--; + is->pictq_cond.notify_one (); + is->pictq_mutex.unlock (); } int queue_picture(VideoState *is, AVFrame *pFrame, double pts) From 90294c589ba3f79e2c760dcd3317d4b30b035710 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 13 Dec 2012 18:24:57 -0800 Subject: [PATCH 106/916] Use a volatile bool for the refresh --- apps/openmw/mwrender/videoplayer.cpp | 10 +++++----- apps/openmw/mwrender/videoplayer.hpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index a6e033216..6307a0028 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -411,10 +411,10 @@ public: }; - void timer_callback (boost::system_time t, VideoState* is) + void timer_callback(boost::system_time t, VideoState* is) { boost::this_thread::sleep(t); - is->refresh++; + is->refresh = true; } /* schedule a video refresh in 'delay' ms */ @@ -469,7 +469,7 @@ public: } if(is->pictq_size == 0) { - schedule_refresh(is, 1); + is->refresh = true; return; } @@ -807,7 +807,7 @@ public: is->av_sync_type = DEFAULT_AV_SYNC_TYPE; is->videoStream = -1; is->audioStream = -1; - is->refresh = 0; + is->refresh = false; is->quit = 0; is->stream = Ogre::ResourceGroupManager::getSingleton ().openResource(resourceName); @@ -959,8 +959,8 @@ public: close(); else if(mState->refresh) { + mState->refresh = false; video_refresh_timer(mState); - mState->refresh--; } } diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 689b3ad36..67b619ad2 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -117,8 +117,8 @@ namespace MWRender boost::thread video_thread; volatile int quit; + volatile bool refresh; - int refresh; int display_ready; }; enum { From 5221298a7f99847f3a00e22ddbbf79fb2a89f011 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 01:14:14 -0800 Subject: [PATCH 107/916] Move a couple packet queue methods into the struct --- apps/openmw/mwrender/videoplayer.cpp | 65 +++++++++++++--------------- apps/openmw/mwrender/videoplayer.hpp | 38 +++++++++------- 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 6307a0028..b4fd264ec 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -42,41 +42,38 @@ namespace MWRender return stream->tell(); } - void packet_queue_init(PacketQueue *q) - { memset(q, 0, sizeof(PacketQueue)); } - int packet_queue_put(PacketQueue *q, AVPacket *pkt) + void PacketQueue::put(AVPacket *pkt) { AVPacketList *pkt1; if(av_dup_packet(pkt) < 0) - return -1; + throw std::runtime_error("Failed to duplicate packet"); pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); - if(!pkt1) return -1; + if(!pkt1) throw std::bad_alloc(); pkt1->pkt = *pkt; pkt1->next = NULL; - q->mutex.lock (); + this->mutex.lock (); - if (!q->last_pkt) - q->first_pkt = pkt1; + if(!last_pkt) + this->first_pkt = pkt1; else - q->last_pkt->next = pkt1; - q->last_pkt = pkt1; - q->nb_packets++; - q->size += pkt1->pkt.size; - q->cond.notify_one(); - q->mutex.unlock (); - return 0; + this->last_pkt->next = pkt1; + this->last_pkt = pkt1; + this->nb_packets++; + this->size += pkt1->pkt.size; + this->cond.notify_one(); + + this->mutex.unlock(); } - static int packet_queue_get(PacketQueue *q, AVPacket *pkt, VideoState *is, int block) + int PacketQueue::get(AVPacket *pkt, VideoState *is, int block) { AVPacketList *pkt1; int ret; - boost::unique_lock lock(q->mutex); - + boost::unique_lock lock(this->mutex); for(;;) { if(is->quit) @@ -85,16 +82,18 @@ namespace MWRender break; } - pkt1 = q->first_pkt; - if (pkt1) + pkt1 = this->first_pkt; + if(pkt1) { - q->first_pkt = pkt1->next; - if (!q->first_pkt) - q->last_pkt = NULL; - q->nb_packets--; - q->size -= pkt1->pkt.size; + this->first_pkt = pkt1->next; + if(!this->first_pkt) + this->last_pkt = NULL; + this->nb_packets--; + this->size -= pkt1->pkt.size; + *pkt = pkt1->pkt; av_free(pkt1); + ret = 1; break; } @@ -105,7 +104,7 @@ namespace MWRender break; } - q->cond.wait(lock); + this->cond.wait(lock); } return ret; @@ -116,7 +115,8 @@ namespace MWRender AVPacketList *pkt, *pkt1; this->mutex.lock(); - for(pkt = this->first_pkt; pkt != NULL; pkt = pkt1) { + for(pkt = this->first_pkt; pkt != NULL; pkt = pkt1) + { pkt1 = pkt->next; av_free_packet(&pkt->pkt); av_freep(&pkt); @@ -294,7 +294,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder return -1; /* next packet */ - if(packet_queue_get(&is->audioq, pkt, is, 1) < 0) + if(is->audioq.get(pkt, is, 1) < 0) return -1; /* if update, update the audio clock w/pts */ @@ -630,7 +630,7 @@ public: for(;;) { - if(packet_queue_get(&is->videoq, packet, is, 1) < 0) + if(is->videoq.get(packet, is, 1) < 0) { // means we quit getting packets break; @@ -701,7 +701,6 @@ public: is->audio_diff_threshold = 2.0 * 0.1/* 100 ms */; memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); - packet_queue_init(&is->audioq); decoder.reset(new MovieAudioDecoder(is)); is->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); @@ -722,8 +721,6 @@ public: is->frame_last_delay = 40e-3; is->video_current_pts_time = av_gettime(); - packet_queue_init(&is->videoq); - codecCtx->get_buffer = our_get_buffer; codecCtx->release_buffer = our_release_buffer; is->video_thread = boost::thread(video_thread, is); @@ -764,9 +761,9 @@ public: // Is this a packet from the video stream? if(packet->stream_index == is->videoStream) - packet_queue_put(&is->videoq, packet); + is->videoq.put(packet); else if(packet->stream_index == is->audioStream) - packet_queue_put(&is->audioq, packet); + is->audioq.put(packet); else av_free_packet(packet); } diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 67b619ad2..5dfa3cf56 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -33,10 +33,13 @@ extern "C" namespace MWRender { + struct VideoState; + struct PacketQueue { - PacketQueue () : - first_pkt(NULL), last_pkt(NULL), nb_packets(0), size(0) - {} + PacketQueue() + : first_pkt(NULL), last_pkt(NULL), nb_packets(0), size(0) + { } + AVPacketList *first_pkt, *last_pkt; int nb_packets; int size; @@ -44,20 +47,23 @@ namespace MWRender boost::mutex mutex; boost::condition_variable cond; - void flush (); - }; - struct VideoPicture { - VideoPicture () : - data(NULL), pts(0) - {} - uint8_t* data; + void put(AVPacket *pkt); + int get(AVPacket *pkt, VideoState *is, int block); + void flush(); + }; + + struct VideoPicture { + VideoPicture () : data(NULL), pts(0) + { } + + uint8_t *data; double pts; }; struct VideoState { - VideoState () : - videoStream(-1), audioStream(-1), av_sync_type(0), external_clock(0), + VideoState () + : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock(0), external_clock_time(0), audio_clock(0), audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), frame_last_delay(0), video_clock(0), video_current_pts(0), @@ -68,11 +74,11 @@ namespace MWRender ~VideoState() { - audioq.flush (); + audioq.flush(); videoq.flush(); - if (pictq_size >= 1) - free (pictq[0].data); + if(pictq_size >= 1) + free(pictq[0].data); } int videoStream, audioStream; @@ -82,7 +88,7 @@ namespace MWRender int64_t external_clock_time; double audio_clock; - AVStream *audio_st; + AVStream *audio_st; PacketQueue audioq; AVPacket audio_pkt; double audio_diff_cum; /* used for AV difference average computation */ From 26a09ee7ba3afd56b83442763c1aaaad7846da55 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 01:38:00 -0800 Subject: [PATCH 108/916] Move some methods into their respective class --- apps/openmw/mwrender/videoplayer.cpp | 303 +++++++++++++-------------- apps/openmw/mwrender/videoplayer.hpp | 8 +- 2 files changed, 158 insertions(+), 153 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b4fd264ec..ec68359aa 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -11,123 +11,91 @@ namespace MWRender { - int OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) +void PacketQueue::put(AVPacket *pkt) +{ + AVPacketList *pkt1; + if(av_dup_packet(pkt) < 0) + throw std::runtime_error("Failed to duplicate packet"); + + pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); + if(!pkt1) throw std::bad_alloc(); + pkt1->pkt = *pkt; + pkt1->next = NULL; + + this->mutex.lock (); + + if(!last_pkt) + this->first_pkt = pkt1; + else + this->last_pkt->next = pkt1; + this->last_pkt = pkt1; + this->nb_packets++; + this->size += pkt1->pkt.size; + this->cond.notify_one(); + + this->mutex.unlock(); +} + +int PacketQueue::get(AVPacket *pkt, VideoState *is, int block) +{ + AVPacketList *pkt1; + int ret; + + boost::unique_lock lock(this->mutex); + for(;;) { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; - return stream->read(buf, buf_size); - } - - int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) - { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; - return stream->write(buf, buf_size); - } - - int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence) - { - Ogre::DataStreamPtr stream = static_cast(user_data)->stream; - - whence &= ~AVSEEK_FORCE; - if(whence == AVSEEK_SIZE) - return stream->size(); - if(whence == SEEK_SET) - stream->seek(offset); - else if(whence == SEEK_CUR) - stream->seek(stream->tell()+offset); - else if(whence == SEEK_END) - stream->seek(stream->size()+offset); - else - return -1; - - return stream->tell(); - } - - - void PacketQueue::put(AVPacket *pkt) - { - AVPacketList *pkt1; - if(av_dup_packet(pkt) < 0) - throw std::runtime_error("Failed to duplicate packet"); - - pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); - if(!pkt1) throw std::bad_alloc(); - pkt1->pkt = *pkt; - pkt1->next = NULL; - - this->mutex.lock (); - - if(!last_pkt) - this->first_pkt = pkt1; - else - this->last_pkt->next = pkt1; - this->last_pkt = pkt1; - this->nb_packets++; - this->size += pkt1->pkt.size; - this->cond.notify_one(); - - this->mutex.unlock(); - } - - int PacketQueue::get(AVPacket *pkt, VideoState *is, int block) - { - AVPacketList *pkt1; - int ret; - - boost::unique_lock lock(this->mutex); - for(;;) + if(is->quit) { - if(is->quit) - { - ret = -1; - break; - } - - pkt1 = this->first_pkt; - if(pkt1) - { - this->first_pkt = pkt1->next; - if(!this->first_pkt) - this->last_pkt = NULL; - this->nb_packets--; - this->size -= pkt1->pkt.size; - - *pkt = pkt1->pkt; - av_free(pkt1); - - ret = 1; - break; - } - - if (!block) - { - ret = 0; - break; - } - - this->cond.wait(lock); + ret = -1; + break; } - return ret; - } - - void PacketQueue::flush() - { - AVPacketList *pkt, *pkt1; - - this->mutex.lock(); - for(pkt = this->first_pkt; pkt != NULL; pkt = pkt1) + pkt1 = this->first_pkt; + if(pkt1) { - pkt1 = pkt->next; - av_free_packet(&pkt->pkt); - av_freep(&pkt); + this->first_pkt = pkt1->next; + if(!this->first_pkt) + this->last_pkt = NULL; + this->nb_packets--; + this->size -= pkt1->pkt.size; + + *pkt = pkt1->pkt; + av_free(pkt1); + + ret = 1; + break; } - this->last_pkt = NULL; - this->first_pkt = NULL; - this->nb_packets = 0; - this->size = 0; - this->mutex.unlock (); + + if (!block) + { + ret = 0; + break; + } + + this->cond.wait(lock); } + return ret; +} + +void PacketQueue::flush() +{ + AVPacketList *pkt, *pkt1; + + this->mutex.lock(); + for(pkt = this->first_pkt; pkt != NULL; pkt = pkt1) + { + pkt1 = pkt->next; + av_free_packet(&pkt->pkt); + av_freep(&pkt); + } + this->last_pkt = NULL; + this->first_pkt = NULL; + this->nb_packets = 0; + this->size = 0; + this->mutex.unlock (); +} + double get_audio_clock(VideoState *is) { @@ -411,6 +379,38 @@ public: }; +int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->stream; + return stream->read(buf, buf_size); +} + +int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->stream; + return stream->write(buf, buf_size); +} + +int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whence) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->stream; + + whence &= ~AVSEEK_FORCE; + if(whence == AVSEEK_SIZE) + return stream->size(); + if(whence == SEEK_SET) + stream->seek(offset); + else if(whence == SEEK_CUR) + stream->seek(stream->tell()+offset); + else if(whence == SEEK_END) + stream->seek(stream->size()+offset); + else + return -1; + + return stream->tell(); +} + + void timer_callback(boost::system_time t, VideoState* is) { boost::this_thread::sleep(t); @@ -793,7 +793,7 @@ public: return 0; } - void init_state(VideoState *is, const std::string& resourceName) + void VideoState::init(const std::string& resourceName) { try { @@ -801,90 +801,90 @@ public: int audio_index = -1; unsigned int i; - is->av_sync_type = DEFAULT_AV_SYNC_TYPE; - is->videoStream = -1; - is->audioStream = -1; - is->refresh = false; - is->quit = 0; + this->av_sync_type = DEFAULT_AV_SYNC_TYPE; + this->videoStream = -1; + this->audioStream = -1; + this->refresh = false; + this->quit = 0; - is->stream = Ogre::ResourceGroupManager::getSingleton ().openResource(resourceName); - if(is->stream.isNull()) + this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); + if(this->stream.isNull()) throw std::runtime_error("Failed to open video resource"); - is->format_ctx = avformat_alloc_context(); - - is->format_ctx->pb = avio_alloc_context(NULL, 0, 0, is, OgreResource_Read, OgreResource_Write, OgreResource_Seek); - if(!is->format_ctx->pb) + this->format_ctx = avformat_alloc_context(); + this->format_ctx->pb = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if(!this->format_ctx->pb) { - avformat_free_context(is->format_ctx); + avformat_free_context(this->format_ctx); throw std::runtime_error("Failed to allocate ioContext "); } // Open video file /// \todo leak here, ffmpeg or valgrind bug ? - if (avformat_open_input(&is->format_ctx, resourceName.c_str(), NULL, NULL)) + if (avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) { // "Note that a user-supplied AVFormatContext will be freed on failure." - is->format_ctx = NULL; + this->format_ctx = NULL; throw std::runtime_error("Failed to open video input"); } // Retrieve stream information - if(avformat_find_stream_info(is->format_ctx, NULL) < 0) + if(avformat_find_stream_info(this->format_ctx, NULL) < 0) throw std::runtime_error("Failed to retrieve stream information"); // Dump information about file onto standard error - av_dump_format(is->format_ctx, 0, resourceName.c_str(), 0); + av_dump_format(this->format_ctx, 0, resourceName.c_str(), 0); - for(i = 0;i < is->format_ctx->nb_streams;i++) + for(i = 0;i < this->format_ctx->nb_streams;i++) { - if(is->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) + if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) video_index = i; - if(is->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) + if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) audio_index = i; } if(audio_index >= 0) - stream_component_open(is, audio_index, is->format_ctx); + stream_component_open(this, audio_index, this->format_ctx); if(video_index >= 0) - stream_component_open(is, video_index, is->format_ctx); + stream_component_open(this, video_index, this->format_ctx); } - catch (std::runtime_error& e) + catch(std::runtime_error& e) { - is->quit = 1; + this->quit = 1; throw; } - catch (Ogre::Exception& e) + catch(Ogre::Exception& e) { - is->quit = 1; + this->quit = 1; throw; } } - void deinit_state(VideoState *is) + void VideoState::deinit() { - is->audioq.cond.notify_one (); - is->videoq.cond.notify_one (); + this->audioq.cond.notify_one(); + this->videoq.cond.notify_one(); - is->parse_thread.join(); - is->video_thread.join(); + this->parse_thread.join(); + this->video_thread.join(); - if(is->audioStream >= 0) - avcodec_close(is->audio_st->codec); - if(is->videoStream >= 0) - avcodec_close(is->video_st->codec); + if(this->audioStream >= 0) + avcodec_close(this->audio_st->codec); + if(this->videoStream >= 0) + avcodec_close(this->video_st->codec); - if (is->sws_context) - sws_freeContext(is->sws_context); + if(this->sws_context) + sws_freeContext(this->sws_context); - if (is->format_ctx) + if(this->format_ctx) { - AVIOContext *ioContext = is->format_ctx->pb; - avformat_close_input(&is->format_ctx); + AVIOContext *ioContext = this->format_ctx->pb; + avformat_close_input(&this->format_ctx); av_free(ioContext); } } + VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) : mState(NULL) , mSceneMgr(sceneMgr) @@ -941,8 +941,7 @@ public: MWBase::Environment::get().getSoundManager()->pauseAllSounds(); mState = new VideoState; - - init_state(mState, resourceName); + mState->init(resourceName); schedule_refresh(mState, 40); mState->parse_thread = boost::thread(decode_thread, mState); @@ -970,7 +969,7 @@ public: void VideoPlayer::close() { mState->quit = 1; - deinit_state(mState); + mState->deinit(); delete mState; mState = NULL; diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 5dfa3cf56..82a7083ae 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -71,7 +71,6 @@ namespace MWRender pictq_windex(0), quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) {} - ~VideoState() { audioq.flush(); @@ -81,6 +80,13 @@ namespace MWRender free(pictq[0].data); } + void init(const std::string& resourceName); + void deinit(); + + static int OgreResource_Read(void *user_data, uint8_t *buf, int buf_size); + static int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size); + static int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence); + int videoStream, audioStream; int av_sync_type; From c2b711d195c6ce6702f693703c249b22add7f2e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 02:36:29 -0800 Subject: [PATCH 109/916] Move some more methods to the class they're part of --- apps/openmw/mwrender/videoplayer.cpp | 892 +++++++++++++-------------- apps/openmw/mwrender/videoplayer.hpp | 14 + 2 files changed, 449 insertions(+), 457 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index ec68359aa..4334bc634 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -97,32 +97,33 @@ void PacketQueue::flush() } - double get_audio_clock(VideoState *is) - { - return is->AudioTrack->getTimeOffset(); - } +static double get_audio_clock(VideoState *is) +{ + return is->AudioTrack->getTimeOffset(); +} - double get_video_clock(VideoState *is) - { - double delta; +static double get_video_clock(VideoState *is) +{ + double delta; - delta = (av_gettime() - is->video_current_pts_time) / 1000000.0; - return is->video_current_pts + delta; - } + delta = (av_gettime() - is->video_current_pts_time) / 1000000.0; + return is->video_current_pts + delta; +} - double get_external_clock(VideoState *is) - { - return av_gettime() / 1000000.0; - } +static double get_external_clock(VideoState *is) +{ + return av_gettime() / 1000000.0; +} + +static double get_master_clock(VideoState *is) +{ + if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) + return get_video_clock(is); + if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) + return get_audio_clock(is); + return get_external_clock(is); +} - double get_master_clock(VideoState *is) - { - if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) - return get_video_clock(is); - if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) - return get_audio_clock(is); - return get_external_clock(is); - } class MovieAudioDecoder : public MWSound::Sound_Decoder { @@ -411,479 +412,459 @@ int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whenc } - void timer_callback(boost::system_time t, VideoState* is) +void VideoState::timer_callback(VideoState* is, boost::system_time t) +{ + boost::this_thread::sleep(t); + is->refresh = true; +} + +/* schedule a video refresh in 'delay' ms */ +void VideoState::schedule_refresh(int delay) +{ + boost::system_time t = boost::get_system_time() + boost::posix_time::milliseconds(delay); + boost::thread(boost::bind(&timer_callback, this, t)).detach(); +} + + +void VideoState::video_display() +{ + VideoPicture *vp = &this->pictq[this->pictq_rindex]; + + if(this->video_st->codec->width != 0 && this->video_st->codec->height != 0) { - boost::this_thread::sleep(t); - is->refresh = true; + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("VideoTexture"); + if(texture.isNull () || static_cast(texture->getWidth()) != this->video_st->codec->width + || static_cast(texture->getHeight()) != this->video_st->codec->height) + { + Ogre::TextureManager::getSingleton ().remove ("VideoTexture"); + texture = Ogre::TextureManager::getSingleton().createManual( + "VideoTexture", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + this->video_st->codec->width, this->video_st->codec->height, + 0, + Ogre::PF_BYTE_RGBA, + Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); + } + Ogre::PixelBox pb(this->video_st->codec->width, this->video_st->codec->height, 1, Ogre::PF_BYTE_RGBA, vp->data); + Ogre::HardwarePixelBufferSharedPtr buffer = texture->getBuffer(); + buffer->blitFromMemory(pb); + this->display_ready = 1; } - /* schedule a video refresh in 'delay' ms */ - static void schedule_refresh(VideoState *is, int delay) + free(vp->data); +} + +void VideoState::video_refresh_timer() +{ + VideoPicture *vp; + double actual_delay, delay, sync_threshold, ref_clock, diff; + + if(!this->video_st) { - boost::system_time t = boost::get_system_time() + boost::posix_time::milliseconds(delay); - boost::thread(boost::bind(&timer_callback, t, is)).detach(); + this->schedule_refresh(100); + return; + } + if(this->pictq_size == 0) + { + this->refresh = true; + return; } - void video_display(VideoState *is) + vp = &this->pictq[this->pictq_rindex]; + + this->video_current_pts = vp->pts; + this->video_current_pts_time = av_gettime(); + + delay = vp->pts - this->frame_last_pts; /* the pts from last time */ + if(delay <= 0 || delay >= 1.0) { + /* if incorrect delay, use previous one */ + delay = this->frame_last_delay; + } + /* save for next time */ + this->frame_last_delay = delay; + this->frame_last_pts = vp->pts; + + /* update delay to sync to audio if not master source */ + if(this->av_sync_type != AV_SYNC_VIDEO_MASTER) { - VideoPicture *vp; + ref_clock = get_master_clock(this); + diff = vp->pts - ref_clock; - vp = &is->pictq[is->pictq_rindex]; - - if (is->video_st->codec->width != 0 && is->video_st->codec->height != 0) + /* Skip or repeat the frame. Take delay into account + FFPlay still doesn't "know if this is the best guess." */ + sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; + if(fabs(diff) < AV_NOSYNC_THRESHOLD) { - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().getByName("VideoTexture"); - if (texture.isNull () || static_cast(texture->getWidth()) != is->video_st->codec->width - || static_cast(texture->getHeight()) != is->video_st->codec->height) - { - Ogre::TextureManager::getSingleton ().remove ("VideoTexture"); - texture = Ogre::TextureManager::getSingleton().createManual( - "VideoTexture", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - is->video_st->codec->width, is->video_st->codec->height, - 0, - Ogre::PF_BYTE_RGBA, - Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); - } - Ogre::PixelBox pb(is->video_st->codec->width, is->video_st->codec->height, 1, Ogre::PF_BYTE_RGBA, vp->data); - Ogre::HardwarePixelBufferSharedPtr buffer = texture->getBuffer(); - buffer->blitFromMemory(pb); - is->display_ready = 1; + if(diff <= -sync_threshold) + delay = 0; + else if(diff >= sync_threshold) + delay = 2 * delay; } + } + this->frame_timer += delay; - free(vp->data); + /* compute the REAL delay */ + actual_delay = this->frame_timer - (av_gettime() / 1000000.0); + if(actual_delay < 0.010) + { + /* Really it should skip the picture instead */ + actual_delay = 0.010; + } + this->schedule_refresh((int)(actual_delay * 1000 + 0.5)); + + /* show the picture! */ + this->video_display(); + + /* update queue for next picture! */ + if(++this->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) + this->pictq_rindex = 0; + this->pictq_mutex.lock(); + this->pictq_size--; + this->pictq_cond.notify_one(); + this->pictq_mutex.unlock(); +} + + +int VideoState::queue_picture(AVFrame *pFrame, double pts) +{ + VideoPicture *vp; + + /* wait until we have a new pic */ + { + boost::unique_lock lock(this->pictq_mutex); + while(this->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !this->quit) + this->pictq_cond.timed_wait(lock, boost::posix_time::milliseconds(1)); + } + if(this->quit) + return -1; + + // windex is set to 0 initially + vp = &this->pictq[this->pictq_windex]; + + // Convert the image into RGBA format for Ogre + if(this->sws_context == NULL) + { + int w = this->video_st->codec->width; + int h = this->video_st->codec->height; + this->sws_context = sws_getContext(w, h, this->video_st->codec->pix_fmt, + w, h, PIX_FMT_RGBA, SWS_BICUBIC, + NULL, NULL, NULL); + if(this->sws_context == NULL) + throw std::runtime_error("Cannot initialize the conversion context!\n"); } + vp->data = (uint8_t*)malloc(this->video_st->codec->width * this->video_st->codec->height * 4); - void video_refresh_timer(void *userdata) + sws_scale(this->sws_context, pFrame->data, pFrame->linesize, + 0, this->video_st->codec->height, &vp->data, this->rgbaFrame->linesize); + + vp->pts = pts; + + // now we inform our display thread that we have a pic ready + this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_QUEUE_SIZE; + this->pictq_mutex.lock(); + this->pictq_size++; + this->pictq_mutex.unlock(); + + return 0; +} + +double VideoState::synchronize_video(AVFrame *src_frame, double pts) +{ + double frame_delay; + + /* if we have pts, set video clock to it */ + if(pts != 0) + this->video_clock = pts; + else + pts = this->video_clock; + + /* update the video clock */ + frame_delay = av_q2d(this->video_st->codec->time_base); + + /* if we are repeating a frame, adjust clock accordingly */ + frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); + this->video_clock += frame_delay; + + return pts; +} + + +/* These are called whenever we allocate a frame + * buffer. We use this to store the global_pts in + * a frame at the time it is allocated. + */ +static uint64_t global_video_pkt_pts = AV_NOPTS_VALUE; +static int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) +{ + int ret = avcodec_default_get_buffer(c, pic); + uint64_t *pts = (uint64_t*)av_malloc(sizeof(uint64_t)); + *pts = global_video_pkt_pts; + pic->opaque = pts; + return ret; +} +static void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) +{ + if(pic) av_freep(&pic->opaque); + avcodec_default_release_buffer(c, pic); +} + + +void VideoState::video_thread_loop(VideoState *self) +{ + AVPacket pkt1, *packet = &pkt1; + int frameFinished; + AVFrame *pFrame; + double pts; + + pFrame = avcodec_alloc_frame(); + + self->rgbaFrame = avcodec_alloc_frame(); + avpicture_alloc((AVPicture*)self->rgbaFrame, PIX_FMT_RGBA, self->video_st->codec->width, self->video_st->codec->height); + + while(self->videoq.get(packet, self, 1) >= 0) { - VideoState *is = (VideoState *)userdata; - VideoPicture *vp; - double actual_delay, delay, sync_threshold, ref_clock, diff; + // Save global pts to be stored in pFrame + global_video_pkt_pts = packet->pts; + // Decode video frame + if(avcodec_decode_video2(self->video_st->codec, pFrame, &frameFinished, packet) < 0) + throw std::runtime_error("Error decoding video frame"); - if(!is->video_st) + pts = 0; + if((uint64_t)packet->dts != AV_NOPTS_VALUE) + pts = packet->dts; + else if(pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) + pts = *(uint64_t*)pFrame->opaque; + pts *= av_q2d(self->video_st->time_base); + + // Did we get a video frame? + if(frameFinished) { - schedule_refresh(is, 100); - return; + pts = self->synchronize_video(pFrame, pts); + if(self->queue_picture(pFrame, pts) < 0) + break; } - if(is->pictq_size == 0) - { - is->refresh = true; - return; - } - - vp = &is->pictq[is->pictq_rindex]; - - is->video_current_pts = vp->pts; - is->video_current_pts_time = av_gettime(); - - delay = vp->pts - is->frame_last_pts; /* the pts from last time */ - if(delay <= 0 || delay >= 1.0) { - /* if incorrect delay, use previous one */ - delay = is->frame_last_delay; - } - /* save for next time */ - is->frame_last_delay = delay; - is->frame_last_pts = vp->pts; - - /* update delay to sync to audio if not master source */ - if(is->av_sync_type != AV_SYNC_VIDEO_MASTER) - { - ref_clock = get_master_clock(is); - diff = vp->pts - ref_clock; - - /* Skip or repeat the frame. Take delay into account - FFPlay still doesn't "know if this is the best guess." */ - sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; - if(fabs(diff) < AV_NOSYNC_THRESHOLD) - { - if(diff <= -sync_threshold) - delay = 0; - else if(diff >= sync_threshold) - delay = 2 * delay; - } - } - - is->frame_timer += delay; - /* computer the REAL delay */ - actual_delay = is->frame_timer - (av_gettime() / 1000000.0); - if(actual_delay < 0.010) - { - /* Really it should skip the picture instead */ - actual_delay = 0.010; - } - schedule_refresh(is, (int)(actual_delay * 1000 + 0.5)); - - /* show the picture! */ - video_display(is); - - /* update queue for next picture! */ - if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) - is->pictq_rindex = 0; - is->pictq_mutex.lock(); - is->pictq_size--; - is->pictq_cond.notify_one (); - is->pictq_mutex.unlock (); + av_free_packet(packet); } - int queue_picture(VideoState *is, AVFrame *pFrame, double pts) + av_free(pFrame); + + avpicture_free((AVPicture*)self->rgbaFrame); + av_free(self->rgbaFrame); +} + +void VideoState::decode_thread_loop(VideoState *self) +{ + AVFormatContext *pFormatCtx = self->format_ctx; + AVPacket pkt1, *packet = &pkt1; + + try { - VideoPicture *vp; - - /* wait until we have a new pic */ - { - boost::unique_lock lock(is->pictq_mutex); - while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !is->quit) - is->pictq_cond.timed_wait(lock, boost::posix_time::milliseconds(1)); - } - - if(is->quit) - return -1; - - // windex is set to 0 initially - vp = &is->pictq[is->pictq_windex]; - - // Convert the image into YUV format that SDL uses - if(is->sws_context == NULL) - { - int w = is->video_st->codec->width; - int h = is->video_st->codec->height; - is->sws_context = sws_getContext(w, h, is->video_st->codec->pix_fmt, - w, h, PIX_FMT_RGBA, SWS_BICUBIC, - NULL, NULL, NULL); - if(is->sws_context == NULL) - throw std::runtime_error("Cannot initialize the conversion context!\n"); - } - - vp->data =(uint8_t*) malloc(is->video_st->codec->width * is->video_st->codec->height * 4); - - sws_scale(is->sws_context, pFrame->data, pFrame->linesize, - 0, is->video_st->codec->height, &vp->data, is->rgbaFrame->linesize); - - vp->pts = pts; - - // now we inform our display thread that we have a pic ready - if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) - is->pictq_windex = 0; - is->pictq_mutex.lock(); - is->pictq_size++; - is->pictq_mutex.unlock(); - - return 0; - } - - double synchronize_video(VideoState *is, AVFrame *src_frame, double pts) - { - double frame_delay; - - if(pts != 0) - { - /* if we have pts, set video clock to it */ - is->video_clock = pts; - } - else - { - /* if we aren't given a pts, set it to the clock */ - pts = is->video_clock; - } - /* update the video clock */ - frame_delay = av_q2d(is->video_st->codec->time_base); - /* if we are repeating a frame, adjust clock accordingly */ - frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); - is->video_clock += frame_delay; - return pts; - } - - uint64_t global_video_pkt_pts = AV_NOPTS_VALUE; - - /* These are called whenever we allocate a frame - * buffer. We use this to store the global_pts in - * a frame at the time it is allocated. - */ - int our_get_buffer(struct AVCodecContext *c, AVFrame *pic) - { - int ret = avcodec_default_get_buffer(c, pic); - uint64_t *pts = (uint64_t*)av_malloc(sizeof(uint64_t)); - *pts = global_video_pkt_pts; - pic->opaque = pts; - return ret; - } - void our_release_buffer(struct AVCodecContext *c, AVFrame *pic) - { - if(pic) av_freep(&pic->opaque); - avcodec_default_release_buffer(c, pic); - } - - int video_thread(void *arg) - { - VideoState *is = (VideoState *)arg; - AVPacket pkt1, *packet = &pkt1; - int frameFinished; - AVFrame *pFrame; - double pts; - - pFrame = avcodec_alloc_frame(); - - is->rgbaFrame = avcodec_alloc_frame(); - avpicture_alloc((AVPicture*)is->rgbaFrame, PIX_FMT_RGBA, is->video_st->codec->width, is->video_st->codec->height); + if(self->videoStream < 0 && self->audioStream < 0) + throw std::runtime_error("No streams to decode"); + // main decode loop for(;;) { - if(is->videoq.get(packet, is, 1) < 0) - { - // means we quit getting packets + if(self->quit) break; + + if((self->audioStream >= 0 && self->audioq.size > MAX_AUDIOQ_SIZE) || + (self->videoStream >= 0 && self->videoq.size > MAX_VIDEOQ_SIZE)) + { + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + continue; } - pts = 0; - // Save global pts to be stored in pFrame - global_video_pkt_pts = packet->pts; - // Decode video frame - if (avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished, packet) < 0) - throw std::runtime_error("Error decoding video frame"); + if(av_read_frame(pFormatCtx, packet) < 0) + break; - if((uint64_t)packet->dts == AV_NOPTS_VALUE && - pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) - pts = *(uint64_t *)pFrame->opaque; - else if((uint64_t)packet->dts != AV_NOPTS_VALUE) - pts = packet->dts; + // Is this a packet from the video stream? + if(packet->stream_index == self->videoStream) + self->videoq.put(packet); + else if(packet->stream_index == self->audioStream) + self->audioq.put(packet); else - pts = 0; - pts *= av_q2d(is->video_st->time_base); - - // Did we get a video frame? - if(frameFinished) - { - pts = synchronize_video(is, pFrame, pts); - if(queue_picture(is, pFrame, pts) < 0) - break; - } - av_free_packet(packet); + av_free_packet(packet); } - - av_free(pFrame); - - avpicture_free((AVPicture *)is->rgbaFrame); - av_free(is->rgbaFrame); - - return 0; + /* all done - wait for it */ + while(!self->quit) + { + // EOF reached, all packets processed, we can exit now + if(self->audioq.nb_packets == 0 && self->videoq.nb_packets == 0) + break; + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + } + } + catch(std::runtime_error& e) { + std::cerr << "An error occured playing the video: " << e.what () << std::endl; + } + catch(Ogre::Exception& e) { + std::cerr << "An error occured playing the video: " << e.getFullDescription () << std::endl; } - int stream_component_open(VideoState *is, int stream_index, AVFormatContext *pFormatCtx) + self->quit = 1; +} + + +int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) +{ + MWSound::DecoderPtr decoder; + AVCodecContext *codecCtx; + AVCodec *codec; + + if(stream_index < 0 || stream_index >= static_cast(pFormatCtx->nb_streams)) + return -1; + + // Get a pointer to the codec context for the video stream + codecCtx = pFormatCtx->streams[stream_index]->codec; + codec = avcodec_find_decoder(codecCtx->codec_id); + if(!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)) { - MWSound::DecoderPtr decoder; - AVCodecContext *codecCtx; - AVCodec *codec; - - if(stream_index < 0 || stream_index >= static_cast(pFormatCtx->nb_streams)) - return -1; - - // Get a pointer to the codec context for the video stream - codecCtx = pFormatCtx->streams[stream_index]->codec; - codec = avcodec_find_decoder(codecCtx->codec_id); - if(!codec || (avcodec_open2(codecCtx, codec, NULL) < 0)) - { - fprintf(stderr, "Unsupported codec!\n"); - return -1; - } - - switch(codecCtx->codec_type) - { - case AVMEDIA_TYPE_AUDIO: - is->audioStream = stream_index; - is->audio_st = pFormatCtx->streams[stream_index]; - - /* averaging filter for audio sync */ - is->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); - is->audio_diff_avg_count = 0; - /* Correct audio only if larger error than this */ - is->audio_diff_threshold = 2.0 * 0.1/* 100 ms */; - - memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); - - decoder.reset(new MovieAudioDecoder(is)); - is->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); - if(!is->AudioTrack) - { - is->audioStream = -1; - avcodec_close(is->audio_st->codec); - is->audio_st = NULL; - return -1; - } - break; - - case AVMEDIA_TYPE_VIDEO: - is->videoStream = stream_index; - is->video_st = pFormatCtx->streams[stream_index]; - - is->frame_timer = (double)av_gettime() / 1000000.0; - is->frame_last_delay = 40e-3; - is->video_current_pts_time = av_gettime(); - - codecCtx->get_buffer = our_get_buffer; - codecCtx->release_buffer = our_release_buffer; - is->video_thread = boost::thread(video_thread, is); - break; - - default: - break; - } - - return 0; + fprintf(stderr, "Unsupported codec!\n"); + return -1; } - int decode_thread(void *arg) + switch(codecCtx->codec_type) { - VideoState *is = (VideoState *)arg; - try + case AVMEDIA_TYPE_AUDIO: + this->audioStream = stream_index; + this->audio_st = pFormatCtx->streams[stream_index]; + + /* averaging filter for audio sync */ + this->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); + this->audio_diff_avg_count = 0; + /* Correct audio only if larger error than this */ + this->audio_diff_threshold = 2.0 * 0.1/* 100 ms */; + + memset(&this->audio_pkt, 0, sizeof(this->audio_pkt)); + + decoder.reset(new MovieAudioDecoder(this)); + this->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); + if(!this->AudioTrack) { - AVFormatContext *pFormatCtx = is->format_ctx; - AVPacket pkt1, *packet = &pkt1; - - if(is->videoStream >= 0 /*|| is->audioStream < 0*/) - { - // main decode loop - for(;;) - { - if(is->quit) - break; - - if((is->audioStream >= 0 && is->audioq.size > MAX_AUDIOQ_SIZE) || - is->videoq.size > MAX_VIDEOQ_SIZE) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - continue; - } - - if(av_read_frame(pFormatCtx, packet) < 0) - break; - - // Is this a packet from the video stream? - if(packet->stream_index == is->videoStream) - is->videoq.put(packet); - else if(packet->stream_index == is->audioStream) - is->audioq.put(packet); - else - av_free_packet(packet); - } - /* all done - wait for it */ - while(!is->quit) - { - // EOF reached, all packets processed, we can exit now - if(is->audioq.nb_packets == 0 && is->videoq.nb_packets == 0) - break; - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - } - } - - is->quit = 1; - } - catch (std::runtime_error& e) - { - std::cerr << "An error occured playing the video: " << e.what () << std::endl; - is->quit = 1; - } - catch (Ogre::Exception& e) - { - std::cerr << "An error occured playing the video: " << e.getFullDescription () << std::endl; - is->quit = 1; - } - - return 0; - } - - void VideoState::init(const std::string& resourceName) - { - try - { - int video_index = -1; - int audio_index = -1; - unsigned int i; - - this->av_sync_type = DEFAULT_AV_SYNC_TYPE; - this->videoStream = -1; this->audioStream = -1; - this->refresh = false; - this->quit = 0; - - this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); - if(this->stream.isNull()) - throw std::runtime_error("Failed to open video resource"); - - this->format_ctx = avformat_alloc_context(); - this->format_ctx->pb = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); - if(!this->format_ctx->pb) - { - avformat_free_context(this->format_ctx); - throw std::runtime_error("Failed to allocate ioContext "); - } - - // Open video file - /// \todo leak here, ffmpeg or valgrind bug ? - if (avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) - { - // "Note that a user-supplied AVFormatContext will be freed on failure." - this->format_ctx = NULL; - throw std::runtime_error("Failed to open video input"); - } - - // Retrieve stream information - if(avformat_find_stream_info(this->format_ctx, NULL) < 0) - throw std::runtime_error("Failed to retrieve stream information"); - - // Dump information about file onto standard error - av_dump_format(this->format_ctx, 0, resourceName.c_str(), 0); - - for(i = 0;i < this->format_ctx->nb_streams;i++) - { - if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) - video_index = i; - if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) - audio_index = i; - } - - if(audio_index >= 0) - stream_component_open(this, audio_index, this->format_ctx); - if(video_index >= 0) - stream_component_open(this, video_index, this->format_ctx); - } - catch(std::runtime_error& e) - { - this->quit = 1; - throw; - } - catch(Ogre::Exception& e) - { - this->quit = 1; - throw; - } - } - - void VideoState::deinit() - { - this->audioq.cond.notify_one(); - this->videoq.cond.notify_one(); - - this->parse_thread.join(); - this->video_thread.join(); - - if(this->audioStream >= 0) avcodec_close(this->audio_st->codec); - if(this->videoStream >= 0) - avcodec_close(this->video_st->codec); - - if(this->sws_context) - sws_freeContext(this->sws_context); - - if(this->format_ctx) - { - AVIOContext *ioContext = this->format_ctx->pb; - avformat_close_input(&this->format_ctx); - av_free(ioContext); + this->audio_st = NULL; + return -1; } + break; + + case AVMEDIA_TYPE_VIDEO: + this->videoStream = stream_index; + this->video_st = pFormatCtx->streams[stream_index]; + + this->frame_timer = (double)av_gettime() / 1000000.0; + this->frame_last_delay = 40e-3; + this->video_current_pts_time = av_gettime(); + + codecCtx->get_buffer = our_get_buffer; + codecCtx->release_buffer = our_release_buffer; + this->video_thread = boost::thread(video_thread_loop, this); + break; + + default: + break; } + return 0; +} + +void VideoState::init(const std::string& resourceName) +{ + try + { + int video_index = -1; + int audio_index = -1; + unsigned int i; + + this->av_sync_type = DEFAULT_AV_SYNC_TYPE; + this->videoStream = -1; + this->audioStream = -1; + this->refresh = false; + this->quit = 0; + + this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); + if(this->stream.isNull()) + throw std::runtime_error("Failed to open video resource"); + + this->format_ctx = avformat_alloc_context(); + this->format_ctx->pb = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if(!this->format_ctx->pb) + { + avformat_free_context(this->format_ctx); + throw std::runtime_error("Failed to allocate ioContext "); + } + + // Open video file + /// \todo leak here, ffmpeg or valgrind bug ? + if (avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) + { + // "Note that a user-supplied AVFormatContext will be freed on failure." + this->format_ctx = NULL; + throw std::runtime_error("Failed to open video input"); + } + + // Retrieve stream information + if(avformat_find_stream_info(this->format_ctx, NULL) < 0) + throw std::runtime_error("Failed to retrieve stream information"); + + // Dump information about file onto standard error + av_dump_format(this->format_ctx, 0, resourceName.c_str(), 0); + + for(i = 0;i < this->format_ctx->nb_streams;i++) + { + if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) + video_index = i; + if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) + audio_index = i; + } + + if(audio_index >= 0) + this->stream_open(audio_index, this->format_ctx); + if(video_index >= 0) + this->stream_open(video_index, this->format_ctx); + + this->schedule_refresh(40); + this->parse_thread = boost::thread(decode_thread_loop, this); + } + catch(std::runtime_error& e) + { + this->quit = 1; + throw; + } + catch(Ogre::Exception& e) + { + this->quit = 1; + throw; + } +} + +void VideoState::deinit() +{ + this->audioq.cond.notify_one(); + this->videoq.cond.notify_one(); + + this->parse_thread.join(); + this->video_thread.join(); + + if(this->audioStream >= 0) + avcodec_close(this->audio_st->codec); + if(this->videoStream >= 0) + avcodec_close(this->video_st->codec); + + if(this->sws_context) + sws_freeContext(this->sws_context); + + if(this->format_ctx) + { + AVIOContext *ioContext = this->format_ctx->pb; + avformat_close_input(&this->format_ctx); + av_free(ioContext); + } +} + VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) : mState(NULL) @@ -942,9 +923,6 @@ int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whenc mState = new VideoState; mState->init(resourceName); - - schedule_refresh(mState, 40); - mState->parse_thread = boost::thread(decode_thread, mState); } void VideoPlayer::update () @@ -956,7 +934,7 @@ int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whenc else if(mState->refresh) { mState->refresh = false; - video_refresh_timer(mState); + mState->video_refresh_timer(); } } diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 82a7083ae..4bbd81a6e 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -83,6 +83,20 @@ namespace MWRender void init(const std::string& resourceName); void deinit(); + int stream_open(int stream_index, AVFormatContext *pFormatCtx); + + static void video_thread_loop(VideoState *is); + static void decode_thread_loop(VideoState *is); + + void video_display(); + void video_refresh_timer(); + + int queue_picture(AVFrame *pFrame, double pts); + double synchronize_video(AVFrame *src_frame, double pts); + + static void timer_callback(VideoState* is, boost::system_time t); + void schedule_refresh(int delay); + static int OgreResource_Read(void *user_data, uint8_t *buf, int buf_size); static int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size); static int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence); From 157cb10f561112fe174346faef925ec6b32219c8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 02:39:46 -0800 Subject: [PATCH 110/916] Fix a 16-bit audio assumption --- apps/openmw/mwrender/videoplayer.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 4334bc634..6271b2f18 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -145,14 +145,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) return samples_size; - double diff, avg_diff, ref_clock; - int wanted_size, min_size, max_size, n; - // int nb_samples; - - n = 2 * is->audio_st->codec->channels; - - ref_clock = get_master_clock(is); - diff = get_audio_clock(is) - ref_clock; + double ref_clock = get_master_clock(is); + double diff = get_audio_clock(is) - ref_clock; if(diff < AV_NOSYNC_THRESHOLD) { // accumulate the diffs @@ -162,12 +156,14 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder is->audio_diff_avg_count++; else { - avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); + double avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); if(fabs(avg_diff) >= is->audio_diff_threshold) { - wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); - min_size = samples_size/n * (100-SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; - max_size = samples_size/n * (100+SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; + int n = av_samples_get_buffer_size(NULL, is->audio_st->codec->channels, 1, + is->audio_st->codec->sample_fmt, 1); + int wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); + int min_size = samples_size/n * (100-SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; + int max_size = samples_size/n * (100+SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; if(wanted_size < min_size) wanted_size = min_size; From 8db5d10f1013ba5735819a479a627587d03b2c9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 03:11:59 -0800 Subject: [PATCH 111/916] Avoid showing a video picture if we're late Ideally we should skip decoding, or at least YUV->RGB conversion, too. --- apps/openmw/mwrender/videoplayer.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 6271b2f18..432cfae3e 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -447,8 +447,6 @@ void VideoState::video_display() buffer->blitFromMemory(pb); this->display_ready = 1; } - - free(vp->data); } void VideoState::video_refresh_timer() @@ -504,17 +502,21 @@ void VideoState::video_refresh_timer() actual_delay = this->frame_timer - (av_gettime() / 1000000.0); if(actual_delay < 0.010) { - /* Really it should skip the picture instead */ - actual_delay = 0.010; + /* Skip this picture */ + this->refresh = true; + } + else + { + this->schedule_refresh((int)(actual_delay * 1000 + 0.5)); + /* show the picture! */ + this->video_display(); } - this->schedule_refresh((int)(actual_delay * 1000 + 0.5)); - /* show the picture! */ - this->video_display(); + free(vp->data); + vp->data = NULL; /* update queue for next picture! */ - if(++this->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) - this->pictq_rindex = 0; + this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; this->pictq_mutex.lock(); this->pictq_size--; this->pictq_cond.notify_one(); @@ -550,13 +552,12 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) throw std::runtime_error("Cannot initialize the conversion context!\n"); } + vp->pts = pts; vp->data = (uint8_t*)malloc(this->video_st->codec->width * this->video_st->codec->height * 4); sws_scale(this->sws_context, pFrame->data, pFrame->linesize, 0, this->video_st->codec->height, &vp->data, this->rgbaFrame->linesize); - vp->pts = pts; - // now we inform our display thread that we have a pic ready this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_QUEUE_SIZE; this->pictq_mutex.lock(); From 4d6c05f6ccd4855f6538cb4f7f5e4961a9316cd3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 03:19:32 -0800 Subject: [PATCH 112/916] Tighten audio skew allowance --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 432cfae3e..b901c097d 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -733,7 +733,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) this->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); this->audio_diff_avg_count = 0; /* Correct audio only if larger error than this */ - this->audio_diff_threshold = 2.0 * 0.1/* 100 ms */; + this->audio_diff_threshold = 2.0 * 0.025/* 25 ms */; memset(&this->audio_pkt, 0, sizeof(this->audio_pkt)); From a6e627001a128948708028170e846243a787f987 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 03:23:04 -0800 Subject: [PATCH 113/916] Avoid a for(;;) construct --- apps/openmw/mwrender/videoplayer.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b901c097d..b9ff81de0 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -662,11 +662,8 @@ void VideoState::decode_thread_loop(VideoState *self) throw std::runtime_error("No streams to decode"); // main decode loop - for(;;) + while(!self->quit) { - if(self->quit) - break; - if((self->audioStream >= 0 && self->audioq.size > MAX_AUDIOQ_SIZE) || (self->videoStream >= 0 && self->videoq.size > MAX_VIDEOQ_SIZE)) { From 2f37d31108f5190ee5312d724431b20b8fabe879 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 04:12:34 -0800 Subject: [PATCH 114/916] Move some definitions into the source file they're used in --- apps/openmw/mwrender/videoplayer.cpp | 18 +++++++++++++++++- apps/openmw/mwrender/videoplayer.hpp | 13 ------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b9ff81de0..9cbac1688 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -8,9 +8,25 @@ #include "../mwsound/sound.hpp" +#define MAX_AUDIOQ_SIZE (5 * 16 * 1024) +#define MAX_VIDEOQ_SIZE (5 * 256 * 1024) +#define AV_SYNC_THRESHOLD 0.01 +#define AV_NOSYNC_THRESHOLD 10.0 +#define SAMPLE_CORRECTION_PERCENT_MAX 10 +#define AUDIO_DIFF_AVG_NB 20 + + namespace MWRender { +enum { + AV_SYNC_AUDIO_MASTER, + AV_SYNC_VIDEO_MASTER, + AV_SYNC_EXTERNAL_MASTER, + + AV_SYNC_DEFAULT = AV_SYNC_EXTERNAL_MASTER +}; + void PacketQueue::put(AVPacket *pkt) { AVPacketList *pkt1; @@ -773,7 +789,7 @@ void VideoState::init(const std::string& resourceName) int audio_index = -1; unsigned int i; - this->av_sync_type = DEFAULT_AV_SYNC_TYPE; + this->av_sync_type = AV_SYNC_DEFAULT; this->videoStream = -1; this->audioStream = -1; this->refresh = false; diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 4bbd81a6e..428907c4a 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -21,15 +21,7 @@ extern "C" #include "../mwbase/soundmanager.hpp" -#define MAX_AUDIOQ_SIZE (5 * 16 * 1024) -#define MAX_VIDEOQ_SIZE (5 * 256 * 1024) -#define AV_SYNC_THRESHOLD 0.01 -#define AV_NOSYNC_THRESHOLD 10.0 -#define SAMPLE_CORRECTION_PERCENT_MAX 10 -#define AUDIO_DIFF_AVG_NB 20 #define VIDEO_PICTURE_QUEUE_SIZE 1 -#define DEFAULT_AV_SYNC_TYPE AV_SYNC_EXTERNAL_MASTER - namespace MWRender { @@ -147,11 +139,6 @@ namespace MWRender int display_ready; }; - enum { - AV_SYNC_AUDIO_MASTER, - AV_SYNC_VIDEO_MASTER, - AV_SYNC_EXTERNAL_MASTER - }; class VideoPlayer From 05c6483257f2947f1ea24b3e102dc8b8e03e60af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 04:35:57 -0800 Subject: [PATCH 115/916] Fix external clock --- apps/openmw/mwrender/videoplayer.cpp | 5 +++-- apps/openmw/mwrender/videoplayer.hpp | 17 ++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 9cbac1688..56f0bc691 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -128,7 +128,7 @@ static double get_video_clock(VideoState *is) static double get_external_clock(VideoState *is) { - return av_gettime() / 1000000.0; + return ((uint64_t)av_gettime()-is->external_clock_base) / 1000000.0; } static double get_master_clock(VideoState *is) @@ -746,7 +746,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) this->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); this->audio_diff_avg_count = 0; /* Correct audio only if larger error than this */ - this->audio_diff_threshold = 2.0 * 0.025/* 25 ms */; + this->audio_diff_threshold = 2.0 * 0.050/* 50 ms */; memset(&this->audio_pkt, 0, sizeof(this->audio_pkt)); @@ -831,6 +831,7 @@ void VideoState::init(const std::string& resourceName) audio_index = i; } + this->external_clock_base = av_gettime(); if(audio_index >= 0) this->stream_open(audio_index, this->format_ctx); if(video_index >= 0) diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 428907c4a..798611d90 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -55,12 +55,12 @@ namespace MWRender struct VideoState { VideoState () - : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock(0), - external_clock_time(0), audio_clock(0), audio_st(NULL), audio_diff_cum(0), - audio_diff_avg_coef(0), audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), - frame_last_pts(0), frame_last_delay(0), video_clock(0), video_current_pts(0), - video_current_pts_time(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), - pictq_windex(0), quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) + : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock_base(0), + audio_clock(0), audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), + audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), + frame_last_delay(0), video_clock(0), video_current_pts(0), video_current_pts_time(0), + video_st(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), + quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) {} ~VideoState() @@ -95,9 +95,8 @@ namespace MWRender int videoStream, audioStream; - int av_sync_type; - double external_clock; /* external clock base */ - int64_t external_clock_time; + int av_sync_type; + uint64_t external_clock_base; double audio_clock; AVStream *audio_st; From 7332ffb0f865e61e2359d816b9156bf1f732652c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 06:02:34 -0800 Subject: [PATCH 116/916] Let the wanted sample size go down to 0 --- apps/openmw/mwrender/videoplayer.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 56f0bc691..4e9dd0ca2 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -178,13 +178,10 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder int n = av_samples_get_buffer_size(NULL, is->audio_st->codec->channels, 1, is->audio_st->codec->sample_fmt, 1); int wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); - int min_size = samples_size/n * (100-SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; int max_size = samples_size/n * (100+SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; - if(wanted_size < min_size) - wanted_size = min_size; - else if (wanted_size > max_size) - wanted_size = max_size; + wanted_size = std::max(0, wanted_size); + wanted_size = std::min(wanted_size, max_size); if(wanted_size < samples_size) { From d66d8a3118926c5577501980ead59ad24ab03026 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 06:43:51 -0800 Subject: [PATCH 117/916] Don't assume we can write beyond the end of the sample buffer --- apps/openmw/mwrender/videoplayer.cpp | 87 ++++++++++++++++------------ 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 4e9dd0ca2..93255dd45 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -151,8 +151,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder VideoState *is; AVFrame *mFrame; - size_t mFramePos; - size_t mFrameSize; + ssize_t mFramePos; + ssize_t mFrameSize; /* Add or subtract samples to get a better sync, return new * audio buffer size */ @@ -175,38 +175,14 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder double avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); if(fabs(avg_diff) >= is->audio_diff_threshold) { - int n = av_samples_get_buffer_size(NULL, is->audio_st->codec->channels, 1, - is->audio_st->codec->sample_fmt, 1); + int n = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * + is->audio_st->codec->channels; int wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); - int max_size = samples_size/n * (100+SAMPLE_CORRECTION_PERCENT_MAX) / 100 * n; wanted_size = std::max(0, wanted_size); - wanted_size = std::min(wanted_size, max_size); + wanted_size = std::min(wanted_size, samples_size*2); - if(wanted_size < samples_size) - { - /* remove samples */ - samples_size = wanted_size; - } - else if(wanted_size > samples_size) - { - uint8_t *samples_end, *q; - int nb; - - /* add samples by copying final sample*/ - nb = (samples_size - wanted_size); - samples_end = samples + samples_size - n; - q = samples_end + n; - - while(nb > 0) - { - memcpy(q, samples_end, n); - q += n; - nb -= n; - } - - samples_size = wanted_size; - } + samples_size = wanted_size; } } } @@ -249,8 +225,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder if(!got_frame) continue; - int smp_size = av_samples_get_buffer_size(NULL, is->audio_st->codec->channels, 1, - is->audio_st->codec->sample_fmt, 1); + int smp_size = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * + is->audio_st->codec->channels; data_size = frame->nb_samples * smp_size; if(data_size <= 0) { @@ -360,19 +336,54 @@ public: double pts; /* We have already sent all our data; get more */ - audio_size = audio_decode_frame(mFrame, &pts); - if(audio_size < 0) + mFrameSize = audio_decode_frame(mFrame, &pts); + if(mFrameSize < 0) { /* If error, we're done */ break; } - mFrameSize = synchronize_audio(mFrame->data[0], audio_size, pts); - mFramePos = 0; + audio_size = synchronize_audio(mFrame->data[0], mFrameSize, pts); + mFramePos = mFrameSize - audio_size; } - size_t len1 = std::min(len - total, mFrameSize-mFramePos); - memcpy(stream, mFrame->data[0]+mFramePos, len1); + size_t len1 = len - total; + if(mFramePos >= 0) + { + len1 = std::min(len1, mFrameSize-mFramePos); + memcpy(stream, mFrame->data[0]+mFramePos, len1); + } + else + { + len1 = std::min(len1, -mFramePos); + + int n = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * + is->audio_st->codec->channels; + + /* add samples by copying the first sample*/ + if(n == 1) + memset(stream, *mFrame->data[0], len1); + else if(n == 2) + { + for(size_t nb = 0;nb < len1;nb += n) + *((int16_t*)(stream+nb)) = *((int16_t*)mFrame->data[0]); + } + else if(n == 4) + { + for(size_t nb = 0;nb < len1;nb += n) + *((int32_t*)(stream+nb)) = *((int32_t*)mFrame->data[0]); + } + else if(n == 8) + { + for(size_t nb = 0;nb < len1;nb += n) + *((int64_t*)(stream+nb)) = *((int64_t*)mFrame->data[0]); + } + else + { + for(size_t nb = 0;nb < len1;nb += n) + memcpy(stream+nb, mFrame->data[0], n); + } + } total += len1; stream += len1; From f97eaec7ab447ab8d0f2818b38118f7cb561ad83 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 07:25:28 -0800 Subject: [PATCH 118/916] Consolidate some code --- apps/openmw/mwrender/videoplayer.cpp | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 93255dd45..396b91c33 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -199,20 +199,15 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder int audio_decode_frame(AVFrame *frame, double *pts_ptr) { AVPacket *pkt = &is->audio_pkt; - int len1, data_size; for(;;) { while(pkt->size > 0) { - int got_frame; + int len1, got_frame; len1 = avcodec_decode_audio4(is->audio_st->codec, frame, &got_frame, pkt); - if(len1 < 0 || len1 > pkt->size) - { - /* if error, skip packet */ - break; - } + if(len1 < 0) break; if(len1 <= pkt->size) { @@ -222,24 +217,18 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder memset(&pkt->data[remaining], 0, pkt->size - remaining); pkt->size -= len1; } - if(!got_frame) - continue; - int smp_size = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * - is->audio_st->codec->channels; - data_size = frame->nb_samples * smp_size; - if(data_size <= 0) - { - /* No data yet, get more frames */ + /* No data yet? Look for more frames */ + if(!got_frame || frame->nb_samples <= 0) continue; - } *pts_ptr = is->audio_clock; - is->audio_clock += (double)(data_size/smp_size) / + is->audio_clock += (double)frame->nb_samples / (double)is->audio_st->codec->sample_rate; /* We have data, return it and come back for more later */ - return data_size; + return frame->nb_samples * av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * + is->audio_st->codec->channels; } if(pkt->data) av_free_packet(pkt); From 582efcdb9bc13bac35abcd9d65a4a7a285a3eeb5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 07:40:19 -0800 Subject: [PATCH 119/916] Always try to resync if the clock difference is large --- apps/openmw/mwrender/videoplayer.cpp | 62 +++++++++++----------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 396b91c33..bdfffd0cb 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -11,7 +11,6 @@ #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) #define AV_SYNC_THRESHOLD 0.01 -#define AV_NOSYNC_THRESHOLD 10.0 #define SAMPLE_CORRECTION_PERCENT_MAX 10 #define AUDIO_DIFF_AVG_NB 20 @@ -161,36 +160,26 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) return samples_size; - double ref_clock = get_master_clock(is); - double diff = get_audio_clock(is) - ref_clock; - if(diff < AV_NOSYNC_THRESHOLD) - { - // accumulate the diffs - is->audio_diff_cum = diff + is->audio_diff_avg_coef * - is->audio_diff_cum; - if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) - is->audio_diff_avg_count++; - else - { - double avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); - if(fabs(avg_diff) >= is->audio_diff_threshold) - { - int n = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * - is->audio_st->codec->channels; - int wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); - - wanted_size = std::max(0, wanted_size); - wanted_size = std::min(wanted_size, samples_size*2); - - samples_size = wanted_size; - } - } - } + // accumulate the clock difference + double diff = get_audio_clock(is) - get_master_clock(is); + is->audio_diff_cum = diff + is->audio_diff_avg_coef * + is->audio_diff_cum; + if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) + is->audio_diff_avg_count++; else { - /* difference is TOO big; reset diff stuff */ - is->audio_diff_avg_count = 0; - is->audio_diff_cum = 0; + double avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); + if(fabs(avg_diff) >= is->audio_diff_threshold) + { + int n = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * + is->audio_st->codec->channels; + int wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); + + wanted_size = std::max(0, wanted_size); + wanted_size = std::min(wanted_size, samples_size*2); + + samples_size = wanted_size; + } } return samples_size; @@ -499,15 +488,12 @@ void VideoState::video_refresh_timer() diff = vp->pts - ref_clock; /* Skip or repeat the frame. Take delay into account - FFPlay still doesn't "know if this is the best guess." */ - sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; - if(fabs(diff) < AV_NOSYNC_THRESHOLD) - { - if(diff <= -sync_threshold) - delay = 0; - else if(diff >= sync_threshold) - delay = 2 * delay; - } + * FFPlay still doesn't "know if this is the best guess." */ + sync_threshold = std::max(delay, AV_SYNC_THRESHOLD); + if(diff <= -sync_threshold) + delay = 0; + else if(diff >= sync_threshold) + delay = 2 * delay; } this->frame_timer += delay; From 71ff90aaee5bcd8208996a66de53ec3ceee2088a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 14 Dec 2012 08:42:37 -0800 Subject: [PATCH 120/916] Don't use sub-frame timing for the video clock --- apps/openmw/mwrender/videoplayer.cpp | 11 +++-------- apps/openmw/mwrender/videoplayer.hpp | 11 +++++------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index bdfffd0cb..fe228d25e 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -119,10 +119,7 @@ static double get_audio_clock(VideoState *is) static double get_video_clock(VideoState *is) { - double delta; - - delta = (av_gettime() - is->video_current_pts_time) / 1000000.0; - return is->video_current_pts + delta; + return is->video_current_pts; } static double get_external_clock(VideoState *is) @@ -469,9 +466,6 @@ void VideoState::video_refresh_timer() vp = &this->pictq[this->pictq_rindex]; - this->video_current_pts = vp->pts; - this->video_current_pts_time = av_gettime(); - delay = vp->pts - this->frame_last_pts; /* the pts from last time */ if(delay <= 0 || delay >= 1.0) { /* if incorrect delay, use previous one */ @@ -481,6 +475,8 @@ void VideoState::video_refresh_timer() this->frame_last_delay = delay; this->frame_last_pts = vp->pts; + this->video_current_pts = vp->pts; + /* update delay to sync to audio if not master source */ if(this->av_sync_type != AV_SYNC_VIDEO_MASTER) { @@ -750,7 +746,6 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) this->frame_timer = (double)av_gettime() / 1000000.0; this->frame_last_delay = 40e-3; - this->video_current_pts_time = av_gettime(); codecCtx->get_buffer = our_get_buffer; codecCtx->release_buffer = our_release_buffer; diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 798611d90..1213ca36c 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -58,9 +58,9 @@ namespace MWRender : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock_base(0), audio_clock(0), audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), - frame_last_delay(0), video_clock(0), video_current_pts(0), video_current_pts_time(0), - video_st(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), - quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) + frame_last_delay(0), video_clock(0), video_current_pts(0), video_st(NULL), + rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), quit(false), + refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) {} ~VideoState() @@ -68,8 +68,8 @@ namespace MWRender audioq.flush(); videoq.flush(); - if(pictq_size >= 1) - free(pictq[0].data); + for(int i = 0;i < VIDEO_PICTURE_QUEUE_SIZE;i++) + free(pictq[i].data); } void init(const std::string& resourceName); @@ -112,7 +112,6 @@ namespace MWRender double frame_last_delay; double video_clock; /// Date: Fri, 14 Dec 2012 09:07:59 -0800 Subject: [PATCH 121/916] Move more stuff to where it should be, and improve cleanup --- apps/openmw/mwrender/videoplayer.cpp | 174 +++++++++++++++++++++------ apps/openmw/mwrender/videoplayer.hpp | 115 ------------------ 2 files changed, 138 insertions(+), 151 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index fe228d25e..2a545f772 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -13,6 +13,7 @@ #define AV_SYNC_THRESHOLD 0.01 #define SAMPLE_CORRECTION_PERCENT_MAX 10 #define AUDIO_DIFF_AVG_NB 20 +#define VIDEO_PICTURE_QUEUE_SIZE 1 namespace MWRender @@ -26,6 +27,135 @@ enum { AV_SYNC_DEFAULT = AV_SYNC_EXTERNAL_MASTER }; +struct PacketQueue { + PacketQueue() + : first_pkt(NULL), last_pkt(NULL), nb_packets(0), size(0) + { } + ~PacketQueue() + { flush(); } + + AVPacketList *first_pkt, *last_pkt; + int nb_packets; + int size; + + boost::mutex mutex; + boost::condition_variable cond; + + void put(AVPacket *pkt); + int get(AVPacket *pkt, VideoState *is, int block); + + void flush(); +}; + +struct VideoPicture { + VideoPicture() : pts(0.0) + { } + + std::vector data; + double pts; +}; + +struct VideoState { + VideoState() + : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock_base(0), + audio_clock(0), audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), + audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), + frame_last_delay(0), video_clock(0), video_current_pts(0), video_st(NULL), + rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), quit(false), + refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) + { } + + ~VideoState() + { } + + void init(const std::string& resourceName); + void deinit(); + + int stream_open(int stream_index, AVFormatContext *pFormatCtx); + + static void video_thread_loop(VideoState *is); + static void decode_thread_loop(VideoState *is); + + void video_display(); + void video_refresh_timer(); + + int queue_picture(AVFrame *pFrame, double pts); + double synchronize_video(AVFrame *src_frame, double pts); + + static void timer_callback(VideoState* is, boost::system_time t); + void schedule_refresh(int delay); + + + double get_audio_clock() + { return this->AudioTrack->getTimeOffset(); } + + double get_video_clock() + { return this->video_current_pts; } + + double get_external_clock() + { return ((uint64_t)av_gettime()-this->external_clock_base) / 1000000.0; } + + double get_master_clock() + { + if(this->av_sync_type == AV_SYNC_VIDEO_MASTER) + return this->get_video_clock(); + if(this->av_sync_type == AV_SYNC_AUDIO_MASTER) + return this->get_audio_clock(); + return this->get_external_clock(); + } + + + static int OgreResource_Read(void *user_data, uint8_t *buf, int buf_size); + static int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size); + static int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence); + + + int videoStream, audioStream; + + int av_sync_type; + uint64_t external_clock_base; + + double audio_clock; + AVStream *audio_st; + PacketQueue audioq; + AVPacket audio_pkt; + double audio_diff_cum; /* used for AV difference average computation */ + double audio_diff_avg_coef; + double audio_diff_threshold; + int audio_diff_avg_count; + + double frame_timer; + double frame_last_pts; + double frame_last_delay; + double video_clock; ///AudioTrack->getTimeOffset(); -} - -static double get_video_clock(VideoState *is) -{ - return is->video_current_pts; -} - -static double get_external_clock(VideoState *is) -{ - return ((uint64_t)av_gettime()-is->external_clock_base) / 1000000.0; -} - -static double get_master_clock(VideoState *is) -{ - if(is->av_sync_type == AV_SYNC_VIDEO_MASTER) - return get_video_clock(is); - if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) - return get_audio_clock(is); - return get_external_clock(is); -} - - class MovieAudioDecoder : public MWSound::Sound_Decoder { static void fail(const std::string &str) @@ -158,7 +263,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder return samples_size; // accumulate the clock difference - double diff = get_audio_clock(is) - get_master_clock(is); + double diff = is->get_audio_clock() - is->get_master_clock(); is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum; if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) @@ -441,7 +546,7 @@ void VideoState::video_display() Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); } - Ogre::PixelBox pb(this->video_st->codec->width, this->video_st->codec->height, 1, Ogre::PF_BYTE_RGBA, vp->data); + Ogre::PixelBox pb(this->video_st->codec->width, this->video_st->codec->height, 1, Ogre::PF_BYTE_RGBA, &vp->data[0]); Ogre::HardwarePixelBufferSharedPtr buffer = texture->getBuffer(); buffer->blitFromMemory(pb); this->display_ready = 1; @@ -451,7 +556,7 @@ void VideoState::video_display() void VideoState::video_refresh_timer() { VideoPicture *vp; - double actual_delay, delay, sync_threshold, ref_clock, diff; + double actual_delay, delay; if(!this->video_st) { @@ -480,12 +585,11 @@ void VideoState::video_refresh_timer() /* update delay to sync to audio if not master source */ if(this->av_sync_type != AV_SYNC_VIDEO_MASTER) { - ref_clock = get_master_clock(this); - diff = vp->pts - ref_clock; + double diff = this->get_video_clock() - this->get_master_clock(); /* Skip or repeat the frame. Take delay into account * FFPlay still doesn't "know if this is the best guess." */ - sync_threshold = std::max(delay, AV_SYNC_THRESHOLD); + double sync_threshold = std::max(delay, AV_SYNC_THRESHOLD); if(diff <= -sync_threshold) delay = 0; else if(diff >= sync_threshold) @@ -507,9 +611,6 @@ void VideoState::video_refresh_timer() this->video_display(); } - free(vp->data); - vp->data = NULL; - /* update queue for next picture! */ this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; this->pictq_mutex.lock(); @@ -548,10 +649,11 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) } vp->pts = pts; - vp->data = (uint8_t*)malloc(this->video_st->codec->width * this->video_st->codec->height * 4); + vp->data.resize(this->video_st->codec->width * this->video_st->codec->height * 4); + uint8_t *dst = &vp->data[0]; sws_scale(this->sws_context, pFrame->data, pFrame->linesize, - 0, this->video_st->codec->height, &vp->data, this->rgbaFrame->linesize); + 0, this->video_st->codec->height, &dst, this->rgbaFrame->linesize); // now we inform our display thread that we have a pic ready this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_QUEUE_SIZE; diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 1213ca36c..7d3e4ac02 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -21,127 +21,13 @@ extern "C" #include "../mwbase/soundmanager.hpp" -#define VIDEO_PICTURE_QUEUE_SIZE 1 namespace MWRender { struct VideoState; - struct PacketQueue { - PacketQueue() - : first_pkt(NULL), last_pkt(NULL), nb_packets(0), size(0) - { } - - AVPacketList *first_pkt, *last_pkt; - int nb_packets; - int size; - - boost::mutex mutex; - boost::condition_variable cond; - - void put(AVPacket *pkt); - int get(AVPacket *pkt, VideoState *is, int block); - - void flush(); - }; - - struct VideoPicture { - VideoPicture () : data(NULL), pts(0) - { } - - uint8_t *data; - double pts; - }; - - struct VideoState { - VideoState () - : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock_base(0), - audio_clock(0), audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), - audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), - frame_last_delay(0), video_clock(0), video_current_pts(0), video_st(NULL), - rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), quit(false), - refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) - {} - - ~VideoState() - { - audioq.flush(); - videoq.flush(); - - for(int i = 0;i < VIDEO_PICTURE_QUEUE_SIZE;i++) - free(pictq[i].data); - } - - void init(const std::string& resourceName); - void deinit(); - - int stream_open(int stream_index, AVFormatContext *pFormatCtx); - - static void video_thread_loop(VideoState *is); - static void decode_thread_loop(VideoState *is); - - void video_display(); - void video_refresh_timer(); - - int queue_picture(AVFrame *pFrame, double pts); - double synchronize_video(AVFrame *src_frame, double pts); - - static void timer_callback(VideoState* is, boost::system_time t); - void schedule_refresh(int delay); - - static int OgreResource_Read(void *user_data, uint8_t *buf, int buf_size); - static int OgreResource_Write(void *user_data, uint8_t *buf, int buf_size); - static int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence); - - int videoStream, audioStream; - - int av_sync_type; - uint64_t external_clock_base; - - double audio_clock; - AVStream *audio_st; - PacketQueue audioq; - AVPacket audio_pkt; - double audio_diff_cum; /* used for AV difference average computation */ - double audio_diff_avg_coef; - double audio_diff_threshold; - int audio_diff_avg_count; - - double frame_timer; - double frame_last_pts; - double frame_last_delay; - double video_clock; /// Date: Fri, 14 Dec 2012 23:42:49 -0800 Subject: [PATCH 122/916] Update the queued sample count immediately --- apps/openmw/mwsound/openal_output.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 672e52b56..bfead7843 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -339,8 +339,6 @@ bool OpenAL_SoundStream::process() { try { bool finished = mIsFinished; - ALint samples_unqueued = 0; - ALint samples_queued = 0; ALint processed, state; alGetSourcei(mSource, AL_SOURCE_STATE, &state); @@ -355,7 +353,7 @@ bool OpenAL_SoundStream::process() size_t got; alSourceUnqueueBuffers(mSource, 1, &bufid); - samples_unqueued += getBufferSampleCount(bufid); + mSamplesQueued -= getBufferSampleCount(bufid); processed--; if(finished) @@ -367,7 +365,7 @@ bool OpenAL_SoundStream::process() { alBufferData(bufid, mFormat, &data[0], got, mSampleRate); alSourceQueueBuffers(mSource, 1, &bufid); - samples_queued += getBufferSampleCount(bufid); + mSamplesQueued += getBufferSampleCount(bufid); } } while(processed > 0); throwALerror(); @@ -383,8 +381,6 @@ bool OpenAL_SoundStream::process() throwALerror(); } - mSamplesQueued -= samples_unqueued; - mSamplesQueued += samples_queued; mIsFinished = finished; } catch(std::exception &e) { From 62a995d492ecf02cf0ac02bcec92cd0360736e95 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 00:18:42 -0800 Subject: [PATCH 123/916] Calculate audio sync once per read --- apps/openmw/mwrender/videoplayer.cpp | 36 ++++++++++++---------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 2a545f772..7281e1c3a 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -255,15 +255,17 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder ssize_t mFramePos; ssize_t mFrameSize; - /* Add or subtract samples to get a better sync, return new - * audio buffer size */ - int synchronize_audio(uint8_t *samples, int samples_size, double pts) + /* Add or subtract samples to get a better sync, return number of bytes to + * skip (negative means to duplicate). */ + int synchronize_audio() { if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) - return samples_size; + return 0; + + int sample_skip = 0; // accumulate the clock difference - double diff = is->get_audio_clock() - is->get_master_clock(); + double diff = is->get_master_clock() - is->get_audio_clock(); is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum; if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) @@ -275,19 +277,14 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder { int n = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * is->audio_st->codec->channels; - int wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n); - - wanted_size = std::max(0, wanted_size); - wanted_size = std::min(wanted_size, samples_size*2); - - samples_size = wanted_size; + sample_skip = ((int)(diff * is->audio_st->codec->sample_rate) * n); } } - return samples_size; + return sample_skip; } - int audio_decode_frame(AVFrame *frame, double *pts_ptr) + int audio_decode_frame(AVFrame *frame) { AVPacket *pkt = &is->audio_pkt; @@ -313,7 +310,6 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder if(!got_frame || frame->nb_samples <= 0) continue; - *pts_ptr = is->audio_clock; is->audio_clock += (double)frame->nb_samples / (double)is->audio_st->codec->sample_rate; @@ -406,25 +402,23 @@ public: size_t read(char *stream, size_t len) { + int sample_skip = synchronize_audio(); size_t total = 0; while(total < len) { - if(mFramePos >= mFrameSize) + while(mFramePos >= mFrameSize) { - int audio_size; - double pts; - /* We have already sent all our data; get more */ - mFrameSize = audio_decode_frame(mFrame, &pts); + mFrameSize = audio_decode_frame(mFrame); if(mFrameSize < 0) { /* If error, we're done */ break; } - audio_size = synchronize_audio(mFrame->data[0], mFrameSize, pts); - mFramePos = mFrameSize - audio_size; + mFramePos = std::min(mFrameSize, sample_skip); + sample_skip -= mFramePos; } size_t len1 = len - total; From b41a77648ec9444b3136e9303fc00b59306c6a1d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 02:33:59 -0800 Subject: [PATCH 124/916] Avoid re-reading the source sample to duplicate, to avoid pointer aliasing --- apps/openmw/mwrender/videoplayer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 7281e1c3a..755378c28 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -439,18 +439,21 @@ public: memset(stream, *mFrame->data[0], len1); else if(n == 2) { + const int16_t val = *((int16_t*)mFrame->data[0]); for(size_t nb = 0;nb < len1;nb += n) - *((int16_t*)(stream+nb)) = *((int16_t*)mFrame->data[0]); + *((int16_t*)(stream+nb)) = val; } else if(n == 4) { + const int32_t val = *((int32_t*)mFrame->data[0]); for(size_t nb = 0;nb < len1;nb += n) - *((int32_t*)(stream+nb)) = *((int32_t*)mFrame->data[0]); + *((int32_t*)(stream+nb)) = val; } else if(n == 8) { + const int64_t val = *((int64_t*)mFrame->data[0]); for(size_t nb = 0;nb < len1;nb += n) - *((int64_t*)(stream+nb)) = *((int64_t*)mFrame->data[0]); + *((int64_t*)(stream+nb)) = val; } else { From eb0e8d9e37043e8d9e312ed7a22fcf9ca96d0f2c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 02:50:59 -0800 Subject: [PATCH 125/916] Simplify PacketQueue::get --- apps/openmw/mwrender/videoplayer.cpp | 32 +++++++--------------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 755378c28..e54b4c5d9 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -42,7 +42,7 @@ struct PacketQueue { boost::condition_variable cond; void put(AVPacket *pkt); - int get(AVPacket *pkt, VideoState *is, int block); + int get(AVPacket *pkt, VideoState *is); void flush(); }; @@ -181,21 +181,12 @@ void PacketQueue::put(AVPacket *pkt) this->mutex.unlock(); } -int PacketQueue::get(AVPacket *pkt, VideoState *is, int block) +int PacketQueue::get(AVPacket *pkt, VideoState *is) { - AVPacketList *pkt1; - int ret; - boost::unique_lock lock(this->mutex); - for(;;) + while(!is->quit) { - if(is->quit) - { - ret = -1; - break; - } - - pkt1 = this->first_pkt; + AVPacketList *pkt1 = this->first_pkt; if(pkt1) { this->first_pkt = pkt1->next; @@ -207,20 +198,13 @@ int PacketQueue::get(AVPacket *pkt, VideoState *is, int block) *pkt = pkt1->pkt; av_free(pkt1); - ret = 1; - break; - } - - if (!block) - { - ret = 0; - break; + return 1; } this->cond.wait(lock); } - return ret; + return -1; } void PacketQueue::flush() @@ -324,7 +308,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder return -1; /* next packet */ - if(is->audioq.get(pkt, is, 1) < 0) + if(is->audioq.get(pkt, is) < 0) return -1; /* if update, update the audio clock w/pts */ @@ -714,7 +698,7 @@ void VideoState::video_thread_loop(VideoState *self) self->rgbaFrame = avcodec_alloc_frame(); avpicture_alloc((AVPicture*)self->rgbaFrame, PIX_FMT_RGBA, self->video_st->codec->width, self->video_st->codec->height); - while(self->videoq.get(packet, self, 1) >= 0) + while(self->videoq.get(packet, self) >= 0) { // Save global pts to be stored in pFrame global_video_pkt_pts = packet->pts; From d50698d7d1598e79fa6fb6bbfbfc47f5bc386b9f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 04:01:52 -0800 Subject: [PATCH 126/916] Clean up the rectangle and scene node used for displaying the video --- apps/openmw/mwrender/videoplayer.cpp | 195 ++++++++++++++------------- apps/openmw/mwrender/videoplayer.hpp | 3 +- 2 files changed, 106 insertions(+), 92 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index e54b4c5d9..5921a4e6f 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -938,103 +938,116 @@ void VideoState::deinit() } - VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) - : mState(NULL) - , mSceneMgr(sceneMgr) - { - mVideoMaterial = Ogre::MaterialManager::getSingleton ().create("VideoMaterial", "General"); - mVideoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(); +VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) + : mState(NULL) + , mSceneMgr(sceneMgr) + , mVideoMaterial(NULL) + , mRectangle(NULL) + , mNode(NULL) +{ + mVideoMaterial = Ogre::MaterialManager::getSingleton().create("VideoMaterial", "General"); + mVideoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState()->setTextureName("black.png"); - mRectangle = new Ogre::Rectangle2D(true); - mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); - mRectangle->setMaterial("VideoMaterial"); - mRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY+1); - // Use infinite AAB to always stay visible - Ogre::AxisAlignedBox aabInf; - aabInf.setInfinite(); - mRectangle->setBoundingBox(aabInf); - // Attach background to the scene - Ogre::SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(mRectangle); - mRectangle->setVisible(false); - mRectangle->setVisibilityFlags (0x1); + mRectangle = new Ogre::Rectangle2D(true); + mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); + mRectangle->setMaterial("VideoMaterial"); + mRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY+1); + + // Use infinite AAB to always stay visible + Ogre::AxisAlignedBox aabInf; + aabInf.setInfinite(); + mRectangle->setBoundingBox(aabInf); + + // Attach background to the scene + mNode = sceneMgr->getRootSceneNode()->createChildSceneNode(); + mNode->attachObject(mRectangle); + + mRectangle->setVisible(false); + mRectangle->setVisibilityFlags(0x1); +} + +VideoPlayer::~VideoPlayer() +{ + if(mState) + close(); + + if(mNode) + mSceneMgr->destroySceneNode(mNode); + mNode = NULL; + + if(mRectangle) + delete mRectangle; + mRectangle = NULL; +} + +void VideoPlayer::playVideo(const std::string &resourceName) +{ + // Register all formats and codecs + av_register_all(); + + if(mState) + close(); + + mRectangle->setVisible(true); + + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Video); + + // Turn off rendering except the GUI + mSceneMgr->clearSpecialCaseRenderQueues(); + // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work. + for(int i = 0;i < Ogre::RENDER_QUEUE_MAX;++i) + { + if(i > 0 && i < 96) + mSceneMgr->addSpecialCaseRenderQueue(i); } + mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - VideoPlayer::~VideoPlayer () + MWBase::Environment::get().getSoundManager()->pauseAllSounds(); + + mState = new VideoState; + mState->init(resourceName); +} + +void VideoPlayer::update () +{ + if(mState) { - if (mState) + if(mState->quit) close(); - } - - void VideoPlayer::playVideo (const std::string &resourceName) - { - // Register all formats and codecs - av_register_all(); - - if (mState) - close(); - - mRectangle->setVisible(true); - - MWBase::Environment::get().getWindowManager ()->pushGuiMode (MWGui::GM_Video); - - // Turn off rendering except the GUI - mSceneMgr->clearSpecialCaseRenderQueues(); - // SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work. - for (int i = 0; i < Ogre::RENDER_QUEUE_MAX; ++i) + else if(mState->refresh) { - if (i > 0 && i < 96) - mSceneMgr->addSpecialCaseRenderQueue(i); + mState->refresh = false; + mState->video_refresh_timer(); + // Would be nice not to do this all the time... + if(mState->display_ready) + mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("VideoTexture"); } - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - - MWBase::Environment::get().getSoundManager()->pauseAllSounds(); - - mState = new VideoState; - mState->init(resourceName); - } - - void VideoPlayer::update () - { - if(mState) - { - if(mState->quit) - close(); - else if(mState->refresh) - { - mState->refresh = false; - mState->video_refresh_timer(); - } - } - - if (mState && mState->display_ready && !Ogre::TextureManager::getSingleton ().getByName ("VideoTexture").isNull ()) - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("VideoTexture"); - else - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState (0)->setTextureName ("black.png"); - } - - void VideoPlayer::close() - { - mState->quit = 1; - mState->deinit(); - - delete mState; - mState = NULL; - - MWBase::Environment::get().getSoundManager()->resumeAllSounds(); - - mRectangle->setVisible (false); - MWBase::Environment::get().getWindowManager ()->removeGuiMode (MWGui::GM_Video); - - mSceneMgr->clearSpecialCaseRenderQueues(); - mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - } - - bool VideoPlayer::isPlaying () - { - return mState != NULL; } } + +void VideoPlayer::close() +{ + mState->quit = 1; + mState->deinit(); + + delete mState; + mState = NULL; + + MWBase::Environment::get().getSoundManager()->resumeAllSounds(); + + mRectangle->setVisible(false); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Video); + + mSceneMgr->clearSpecialCaseRenderQueues(); + mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); +} + +bool VideoPlayer::isPlaying () +{ + return mState != NULL; +} + +} diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 7d3e4ac02..9060241bd 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -45,8 +45,9 @@ namespace MWRender VideoState* mState; Ogre::SceneManager* mSceneMgr; - Ogre::Rectangle2D* mRectangle; Ogre::MaterialPtr mVideoMaterial; + Ogre::Rectangle2D* mRectangle; + Ogre::SceneNode* mNode; }; } From da44141b95dc712d3872c5398cf4b21adb5f3ed7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 04:17:28 -0800 Subject: [PATCH 127/916] Avoid creating extra texture unit states on the video material --- apps/openmw/mwrender/videoplayer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 5921a4e6f..4f42c3fb6 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -949,7 +949,10 @@ VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) mVideoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState()->setTextureName("black.png"); + if(mVideoMaterial->getTechnique(0)->getPass(0)->getNumTextureUnitStates() == 0) + mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState()->setTextureName("black.png"); + else + mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); mRectangle = new Ogre::Rectangle2D(true); mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); From 6008cf0d1511f3c2a05c6696bbd457bcfd181236 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 05:02:01 -0800 Subject: [PATCH 128/916] Remove unneeded video_current_pts field --- apps/openmw/mwrender/videoplayer.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 4f42c3fb6..e7bdfab91 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -60,9 +60,9 @@ struct VideoState { : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock_base(0), audio_clock(0), audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), - frame_last_delay(0), video_clock(0), video_current_pts(0), video_st(NULL), - rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), quit(false), - refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) + frame_last_delay(0), video_clock(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), + pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), format_ctx(0), + sws_context(NULL), display_ready(0) { } ~VideoState() @@ -90,7 +90,7 @@ struct VideoState { { return this->AudioTrack->getTimeOffset(); } double get_video_clock() - { return this->video_current_pts; } + { return this->frame_last_pts; } double get_external_clock() { return ((uint64_t)av_gettime()-this->external_clock_base) / 1000000.0; } @@ -128,7 +128,6 @@ struct VideoState { double frame_last_pts; double frame_last_delay; double video_clock; ///frame_last_delay = delay; this->frame_last_pts = vp->pts; - this->video_current_pts = vp->pts; - /* update delay to sync to audio if not master source */ if(this->av_sync_type != AV_SYNC_VIDEO_MASTER) { From db23c8152e5f0030fea540364ac69d5dc9cff7ab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 07:33:27 -0800 Subject: [PATCH 129/916] Only duplicate AVPackets as needed Packets that don't have a destruct method are using static memory, which will only be valid until the next av_read_frame call. Otherwise, it's already dynamically allocated and will remain valid. --- apps/openmw/mwrender/videoplayer.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index e7bdfab91..bfcb92745 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -158,14 +158,21 @@ struct VideoState { void PacketQueue::put(AVPacket *pkt) { AVPacketList *pkt1; - if(av_dup_packet(pkt) < 0) - throw std::runtime_error("Failed to duplicate packet"); - pkt1 = (AVPacketList*)av_malloc(sizeof(AVPacketList)); if(!pkt1) throw std::bad_alloc(); pkt1->pkt = *pkt; pkt1->next = NULL; + if(pkt1->pkt.destruct == NULL) + { + if(av_dup_packet(&pkt1->pkt) < 0) + { + av_free(pkt1); + throw std::runtime_error("Failed to duplicate packet"); + } + av_free_packet(pkt); + } + this->mutex.lock (); if(!last_pkt) From 74773454814a0106821574e28b8d2d13594aeefa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Dec 2012 17:10:21 +0100 Subject: [PATCH 130/916] fixed video material --- apps/openmw/mwrender/videoplayer.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index bfcb92745..407f1c212 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -407,7 +407,7 @@ public: break; } - mFramePos = std::min(mFrameSize, sample_skip); + mFramePos = std::min(static_cast(mFrameSize), sample_skip); sample_skip -= mFramePos; } @@ -949,14 +949,16 @@ VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) , mRectangle(NULL) , mNode(NULL) { - mVideoMaterial = Ogre::MaterialManager::getSingleton().create("VideoMaterial", "General"); - mVideoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); - if(mVideoMaterial->getTechnique(0)->getPass(0)->getNumTextureUnitStates() == 0) + mVideoMaterial = Ogre::MaterialManager::getSingleton().getByName("VideoMaterial", "General"); + if (mVideoMaterial.isNull ()) + { + mVideoMaterial = Ogre::MaterialManager::getSingleton().create("VideoMaterial", "General"); + mVideoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState()->setTextureName("black.png"); - else - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); + } + mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); mRectangle = new Ogre::Rectangle2D(true); mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); @@ -1016,6 +1018,8 @@ void VideoPlayer::playVideo(const std::string &resourceName) mState = new VideoState; mState->init(resourceName); + + mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); } void VideoPlayer::update () From fa1ad381da72c76ea8f5f85c19959630aab7e3ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 08:42:54 -0800 Subject: [PATCH 131/916] Make sure packets are cleaned up properly --- apps/openmw/mwrender/videoplayer.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index bfcb92745..b0bf37154 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -118,7 +118,6 @@ struct VideoState { double audio_clock; AVStream *audio_st; PacketQueue audioq; - AVPacket audio_pkt; double audio_diff_cum; /* used for AV difference average computation */ double audio_diff_avg_coef; double audio_diff_threshold; @@ -239,8 +238,19 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder throw std::runtime_error(str); } + struct AutoAVPacket : public AVPacket { + AutoAVPacket(int size=0) + { + if(av_new_packet(this, size) < 0) + throw std::bad_alloc(); + } + ~AutoAVPacket() + { av_free_packet(this); } + }; + VideoState *is; + AutoAVPacket mPacket; AVFrame *mFrame; ssize_t mFramePos; ssize_t mFrameSize; @@ -276,7 +286,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder int audio_decode_frame(AVFrame *frame) { - AVPacket *pkt = &is->audio_pkt; + AVPacket *pkt = &mPacket; for(;;) { @@ -292,8 +302,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder /* Move the unread data to the front and clear the end bits */ int remaining = pkt->size - len1; memmove(pkt->data, &pkt->data[len1], remaining); - memset(&pkt->data[remaining], 0, pkt->size - remaining); - pkt->size -= len1; + av_shrink_packet(pkt, remaining); } /* No data yet? Look for more frames */ @@ -307,8 +316,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder return frame->nb_samples * av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * is->audio_st->codec->channels; } - if(pkt->data) - av_free_packet(pkt); + av_free_packet(pkt); if(is->quit) return -1; @@ -717,6 +725,8 @@ void VideoState::video_thread_loop(VideoState *self) pts = *(uint64_t*)pFrame->opaque; pts *= av_q2d(self->video_st->time_base); + av_free_packet(packet); + // Did we get a video frame? if(frameFinished) { @@ -724,7 +734,6 @@ void VideoState::video_thread_loop(VideoState *self) if(self->queue_picture(pFrame, pts) < 0) break; } - av_free_packet(packet); } av_free(pFrame); @@ -814,8 +823,6 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) /* Correct audio only if larger error than this */ this->audio_diff_threshold = 2.0 * 0.050/* 50 ms */; - memset(&this->audio_pkt, 0, sizeof(this->audio_pkt)); - decoder.reset(new MovieAudioDecoder(this)); this->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); if(!this->AudioTrack) From 9b3cf5c1593c72dc2e2fe85f02074b57d69e1e93 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 09:14:58 -0800 Subject: [PATCH 132/916] Use a looping thread to trigger refreshes --- apps/openmw/mwrender/videoplayer.cpp | 63 ++++++++++------------------ 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b0bf37154..f6edf9ad9 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -59,7 +59,7 @@ struct VideoState { VideoState() : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock_base(0), audio_clock(0), audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), - audio_diff_threshold(0), audio_diff_avg_count(0), frame_timer(0), frame_last_pts(0), + audio_diff_threshold(0), audio_diff_avg_count(0), frame_last_pts(0), frame_last_delay(0), video_clock(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) @@ -82,8 +82,7 @@ struct VideoState { int queue_picture(AVFrame *pFrame, double pts); double synchronize_video(AVFrame *src_frame, double pts); - static void timer_callback(VideoState* is, boost::system_time t); - void schedule_refresh(int delay); + static void video_refresh(VideoState *is); double get_audio_clock() @@ -123,7 +122,6 @@ struct VideoState { double audio_diff_threshold; int audio_diff_avg_count; - double frame_timer; double frame_last_pts; double frame_last_delay; double video_clock; ///refresh = true; -} - -/* schedule a video refresh in 'delay' ms */ -void VideoState::schedule_refresh(int delay) -{ - boost::system_time t = boost::get_system_time() + boost::posix_time::milliseconds(delay); - boost::thread(boost::bind(&timer_callback, this, t)).detach(); + boost::system_time t = boost::get_system_time(); + while(!is->quit) + { + t += boost::posix_time::milliseconds(is->refresh_rate_ms); + boost::this_thread::sleep(t); + is->refresh = true; + } } @@ -551,18 +550,10 @@ void VideoState::video_display() void VideoState::video_refresh_timer() { VideoPicture *vp; - double actual_delay, delay; + double delay; - if(!this->video_st) - { - this->schedule_refresh(100); - return; - } if(this->pictq_size == 0) - { - this->refresh = true; return; - } vp = &this->pictq[this->pictq_rindex]; @@ -575,6 +566,8 @@ void VideoState::video_refresh_timer() this->frame_last_delay = delay; this->frame_last_pts = vp->pts; + /* FIXME: Syncing should be done in the decoding stage, where frames can be + * skipped or duplicated as needed. */ /* update delay to sync to audio if not master source */ if(this->av_sync_type != AV_SYNC_VIDEO_MASTER) { @@ -588,21 +581,10 @@ void VideoState::video_refresh_timer() else if(diff >= sync_threshold) delay = 2 * delay; } - this->frame_timer += delay; - /* compute the REAL delay */ - actual_delay = this->frame_timer - (av_gettime() / 1000000.0); - if(actual_delay < 0.010) - { - /* Skip this picture */ - this->refresh = true; - } - else - { - this->schedule_refresh((int)(actual_delay * 1000 + 0.5)); - /* show the picture! */ - this->video_display(); - } + this->refresh_rate_ms = std::max(1, (int)(delay*1000.0)); + /* show the picture! */ + this->video_display(); /* update queue for next picture! */ this->pictq_rindex = (this->pictq_rindex+1) % VIDEO_PICTURE_QUEUE_SIZE; @@ -838,12 +820,12 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) this->videoStream = stream_index; this->video_st = pFormatCtx->streams[stream_index]; - this->frame_timer = (double)av_gettime() / 1000000.0; this->frame_last_delay = 40e-3; codecCtx->get_buffer = our_get_buffer; codecCtx->release_buffer = our_release_buffer; this->video_thread = boost::thread(video_thread_loop, this); + this->refresh_thread = boost::thread(video_refresh, this); break; default: @@ -864,6 +846,7 @@ void VideoState::init(const std::string& resourceName) this->av_sync_type = AV_SYNC_DEFAULT; this->videoStream = -1; this->audioStream = -1; + this->refresh_rate_ms = 10; this->refresh = false; this->quit = 0; @@ -909,7 +892,6 @@ void VideoState::init(const std::string& resourceName) if(video_index >= 0) this->stream_open(video_index, this->format_ctx); - this->schedule_refresh(40); this->parse_thread = boost::thread(decode_thread_loop, this); } catch(std::runtime_error& e) @@ -931,6 +913,7 @@ void VideoState::deinit() this->parse_thread.join(); this->video_thread.join(); + this->refresh_thread.join(); if(this->audioStream >= 0) avcodec_close(this->audio_st->codec); From 5ed04ae53ef6465b3cc167f720c58267872a8167 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Dec 2012 19:23:03 +0100 Subject: [PATCH 133/916] added black bars --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++ apps/openmw/mwrender/videoplayer.cpp | 44 +++++++++++++++++++---- apps/openmw/mwrender/videoplayer.hpp | 7 ++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 811d000a9..3abf88cca 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -162,6 +162,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); mVideoPlayer = new VideoPlayer(mRendering.getScene ()); + mVideoPlayer->setResolution (Settings::Manager::getInt ("resolution x", "Video"), Settings::Manager::getInt ("resolution y", "Video")); mSun = 0; @@ -843,6 +844,8 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw) mCompositors->recreate(); mWater->assignTextures(); + mVideoPlayer->setResolution (rw->getWidth(), rw->getHeight()); + const Settings::CategorySettingVector& changed = Settings::Manager::apply(); MWBase::Environment::get().getInputManager()->processChangedSettings(changed); //FIXME MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); // FIXME diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 4f9963de5..11b6d2b8f 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -950,22 +950,41 @@ VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) } mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); + Ogre::MaterialPtr blackMaterial = Ogre::MaterialManager::getSingleton().getByName("BlackBarsMaterial", "General"); + if (blackMaterial.isNull ()) + { + blackMaterial = Ogre::MaterialManager::getSingleton().create("BlackBarsMaterial", "General"); + blackMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); + blackMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + blackMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + blackMaterial->getTechnique(0)->getPass(0)->createTextureUnitState()->setTextureName("black.png"); + } + mRectangle = new Ogre::Rectangle2D(true); mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); mRectangle->setMaterial("VideoMaterial"); - mRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY+1); + mRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY+2); + mBackgroundRectangle = new Ogre::Rectangle2D(true); + mBackgroundRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); + mBackgroundRectangle->setMaterial("BlackBarsMaterial"); + mBackgroundRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY+1); // Use infinite AAB to always stay visible Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); mRectangle->setBoundingBox(aabInf); + mBackgroundRectangle->setBoundingBox(aabInf); // Attach background to the scene mNode = sceneMgr->getRootSceneNode()->createChildSceneNode(); mNode->attachObject(mRectangle); + mBackgroundNode = sceneMgr->getRootSceneNode()->createChildSceneNode(); + mBackgroundNode->attachObject(mBackgroundRectangle); mRectangle->setVisible(false); mRectangle->setVisibilityFlags(0x1); + mBackgroundRectangle->setVisible(false); + mBackgroundRectangle->setVisibilityFlags(0x1); } VideoPlayer::~VideoPlayer() @@ -973,13 +992,11 @@ VideoPlayer::~VideoPlayer() if(mState) close(); - if(mNode) - mSceneMgr->destroySceneNode(mNode); - mNode = NULL; + mSceneMgr->destroySceneNode(mNode); + mSceneMgr->destroySceneNode(mBackgroundNode); - if(mRectangle) - delete mRectangle; - mRectangle = NULL; + delete mRectangle; + delete mBackgroundRectangle; } void VideoPlayer::playVideo(const std::string &resourceName) @@ -991,6 +1008,7 @@ void VideoPlayer::playVideo(const std::string &resourceName) close(); mRectangle->setVisible(true); + mBackgroundRectangle->setVisible(true); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Video); @@ -1025,6 +1043,17 @@ void VideoPlayer::update () // Would be nice not to do this all the time... if(mState->display_ready) mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("VideoTexture"); + + // Correct aspect ratio by adding black bars + int width = (mState->video_st->codec->width); + int height = (mState->video_st->codec->height); + + float screenaspect = static_cast(mWidth) / mHeight; + float videoaspect = static_cast(width) / height; + float aspect_correction = videoaspect / screenaspect; + + mRectangle->setCorners (std::max(-1.f, -1.f * aspect_correction), std::min(1.f, 1.f / aspect_correction), + std::min(1.f, 1.f * aspect_correction), std::max(-1.f, -1.f / aspect_correction)); } } } @@ -1040,6 +1069,7 @@ void VideoPlayer::close() MWBase::Environment::get().getSoundManager()->resumeAllSounds(); mRectangle->setVisible(false); + mBackgroundRectangle->setVisible(false); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Video); mSceneMgr->clearSpecialCaseRenderQueues(); diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index 9060241bd..c82a16e15 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -40,6 +40,8 @@ namespace MWRender bool isPlaying(); + void setResolution (int w, int h) { mWidth = w; mHeight = h; } + private: VideoState* mState; @@ -47,7 +49,12 @@ namespace MWRender Ogre::SceneManager* mSceneMgr; Ogre::MaterialPtr mVideoMaterial; Ogre::Rectangle2D* mRectangle; + Ogre::Rectangle2D* mBackgroundRectangle; Ogre::SceneNode* mNode; + Ogre::SceneNode* mBackgroundNode; + + int mWidth; + int mHeight; }; } From 63e86555b64e33ceb2fdfcdcf4c3fba9ed3292dc Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Dec 2012 19:40:59 +0100 Subject: [PATCH 134/916] use sample_aspect_ratio if available --- apps/openmw/mwrender/videoplayer.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 11b6d2b8f..740da7a12 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1045,15 +1045,16 @@ void VideoPlayer::update () mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("VideoTexture"); // Correct aspect ratio by adding black bars - int width = (mState->video_st->codec->width); - int height = (mState->video_st->codec->height); + double videoaspect = static_cast(mState->video_st->codec->width) / mState->video_st->codec->height; - float screenaspect = static_cast(mWidth) / mHeight; - float videoaspect = static_cast(width) / height; - float aspect_correction = videoaspect / screenaspect; + if (av_q2d(mState->video_st->codec->sample_aspect_ratio) != 0) + videoaspect *= av_q2d(mState->video_st->codec->sample_aspect_ratio); - mRectangle->setCorners (std::max(-1.f, -1.f * aspect_correction), std::min(1.f, 1.f / aspect_correction), - std::min(1.f, 1.f * aspect_correction), std::max(-1.f, -1.f / aspect_correction)); + double screenaspect = static_cast(mWidth) / mHeight; + double aspect_correction = videoaspect / screenaspect; + + mRectangle->setCorners (std::max(-1.0, -1.0 * aspect_correction), std::min(1.0, 1.0 / aspect_correction), + std::min(1.0, 1.0 * aspect_correction), std::max(-1.0, -1.0 / aspect_correction)); } } } From c869444dcf34920d08bc7ef22d6cfe8bfae88140 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 11:31:50 -0800 Subject: [PATCH 135/916] Don't leak the IO context if avformat_open_input fails --- apps/openmw/mwrender/videoplayer.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 740da7a12..0165d9855 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -854,20 +854,20 @@ void VideoState::init(const std::string& resourceName) if(this->stream.isNull()) throw std::runtime_error("Failed to open video resource"); + AVIOContext *ioCtx = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if(!ioCtx) throw std::runtime_error("Failed to allocate AVIOContext"); + this->format_ctx = avformat_alloc_context(); - this->format_ctx->pb = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); - if(!this->format_ctx->pb) - { - avformat_free_context(this->format_ctx); - throw std::runtime_error("Failed to allocate ioContext "); - } + if(this->format_ctx) + this->format_ctx->pb = ioCtx; // Open video file /// \todo leak here, ffmpeg or valgrind bug ? - if (avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) + if(!this->format_ctx || avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) { // "Note that a user-supplied AVFormatContext will be freed on failure." this->format_ctx = NULL; + av_free(ioCtx); throw std::runtime_error("Failed to open video input"); } From a6c3e06e543bef88f25935d1aeb66ff357550f27 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Dec 2012 20:36:17 +0100 Subject: [PATCH 136/916] fixed fog in some cells --- files/materials/objects.shader | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 5ea076342..25624351c 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -227,7 +227,7 @@ float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.y >= waterLevel || waterEnabled != 1) + if (worldPos.y >= waterLevel || waterEnabled != 1.f) caustics = float3(1,1,1); #endif @@ -269,7 +269,7 @@ #if UNDERWATER // regular fog only if fragment is above water - if (worldPos.y > waterLevel) + if (worldPos.y > waterLevel || waterEnabled != 1.f) #endif shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif From edf18a7d6ec12d9519d00e14f5a532c940a463d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 15 Dec 2012 22:01:45 +0100 Subject: [PATCH 137/916] change destruction order to fix crash on exit when a video is playing --- apps/openmw/mwbase/environment.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 9aaa5af85..5a13a50ec 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -128,12 +128,6 @@ float MWBase::Environment::getFrameDuration() const void MWBase::Environment::cleanup() { - delete mInputManager; - mInputManager = 0; - - delete mSoundManager; - mSoundManager = 0; - delete mMechanicsManager; mMechanicsManager = 0; @@ -146,11 +140,17 @@ void MWBase::Environment::cleanup() delete mScriptManager; mScriptManager = 0; + delete mWorld; + mWorld = 0; + + delete mSoundManager; + mSoundManager = 0; + delete mWindowManager; mWindowManager = 0; - delete mWorld; - mWorld = 0; + delete mInputManager; + mInputManager = 0; } const MWBase::Environment& MWBase::Environment::get() From a3bd3a40ca6494494daf69aaff68284c7792f062 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Dec 2012 00:47:29 +0100 Subject: [PATCH 138/916] fix 2 unrelated leaks --- apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 258a40e1c..373546aa8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -225,6 +225,8 @@ WindowManager::~WindowManager() delete mSpellCreationDialog; delete mEnchantingDialog; delete mTrainingWindow; + delete mCountDialog; + delete mQuickKeysMenu; cleanupGarbage(); From 9d86890d9d71da789fc92dd9ea83b00dcd65e76d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 22:13:19 -0800 Subject: [PATCH 139/916] Only use one stream for the ffmpeg decoder --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 165 ++++++++++++------------- apps/openmw/mwsound/ffmpeg_decoder.hpp | 7 +- 2 files changed, 80 insertions(+), 92 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 6e60a7b9e..205dddd35 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -72,39 +72,26 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) /* Used by getAV*Data to search for more compressed data, and buffer it in the * correct stream. It won't buffer data for streams that the app doesn't have a * handle for. */ -bool FFmpeg_Decoder::getNextPacket(int streamidx) +bool FFmpeg_Decoder::getNextPacket() { - PacketList *packet; + if(!mStream.get()) + return false; - packet = (PacketList*)av_malloc(sizeof(*packet)); + PacketList *packet = (PacketList*)av_malloc(sizeof(*packet)); packet->next = NULL; - -next_packet: while(av_read_frame(mFormatCtx, &packet->pkt) >= 0) { - std::vector::iterator iter = mStreams.begin(); - - /* Check each stream the user has a handle for, looking for the one - * this packet belongs to */ - while(iter != mStreams.end()) + /* Check if the packet belongs to this stream */ + if(mStream->mStreamIdx == packet->pkt.stream_index) { - if((*iter)->mStreamIdx == packet->pkt.stream_index) - { - PacketList **last; + PacketList **last; - last = &(*iter)->mPackets; - while(*last != NULL) - last = &(*last)->next; + last = &mStream->mPackets; + while(*last != NULL) + last = &(*last)->next; - *last = packet; - if((*iter)->mStreamIdx == streamidx) - return true; - - packet = (PacketList*)av_malloc(sizeof(*packet)); - packet->next = NULL; - goto next_packet; - } - iter++; + *last = packet; + return true; } /* Free the packet and look for another */ av_free_packet(&packet->pkt); @@ -138,7 +125,7 @@ void *FFmpeg_Decoder::MyStream::getAVAudioData(size_t *length) mDecodedDataSize = 0; next_packet: - if(!mPackets && !mParent->getNextPacket(mStreamIdx)) + if(!mPackets && !mParent->getNextPacket()) return NULL; /* Decode some data, and check for errors */ @@ -173,8 +160,7 @@ next_packet: /* Move the unread data to the front and clear the end bits */ int remaining = mPackets->pkt.size - len; memmove(mPackets->pkt.data, &mPackets->pkt.data[len], remaining); - memset(&mPackets->pkt.data[remaining], 0, mPackets->pkt.size - remaining); - mPackets->pkt.size -= len; + av_shrink_packet(&mPackets->pkt, remaining); } else { @@ -261,35 +247,38 @@ void FFmpeg_Decoder::open(const std::string &fname) if(avformat_find_stream_info(mFormatCtx, NULL) < 0) fail("Failed to find stream info in "+fname); + int audio_idx = -1; for(size_t j = 0;j < mFormatCtx->nb_streams;j++) { if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - std::auto_ptr stream(new MyStream); - stream->mCodecCtx = mFormatCtx->streams[j]->codec; - stream->mStreamIdx = j; - stream->mPackets = NULL; - - AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id); - if(!codec) - { - std::stringstream ss("No codec found for id "); - ss << stream->mCodecCtx->codec_id; - fail(ss.str()); - } - if(avcodec_open2(stream->mCodecCtx, codec, NULL) < 0) - fail("Failed to open audio codec " + std::string(codec->long_name)); - - stream->mDecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); - stream->mDecodedDataSize = 0; - - stream->mParent = this; - mStreams.push_back(stream.release()); + audio_idx = j; break; } } - if(mStreams.empty()) + if(audio_idx == -1) fail("No audio streams in "+fname); + + std::auto_ptr stream(new MyStream); + stream->mCodecCtx = mFormatCtx->streams[audio_idx]->codec; + stream->mStreamIdx = audio_idx; + stream->mPackets = NULL; + + AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id); + if(!codec) + { + std::stringstream ss("No codec found for id "); + ss << stream->mCodecCtx->codec_id; + fail(ss.str()); + } + if(avcodec_open2(stream->mCodecCtx, codec, NULL) < 0) + fail("Failed to open audio codec " + std::string(codec->long_name)); + + stream->mDecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); + stream->mDecodedDataSize = 0; + + stream->mParent = this; + mStream = stream; } catch(std::exception &e) { @@ -301,23 +290,19 @@ void FFmpeg_Decoder::open(const std::string &fname) void FFmpeg_Decoder::close() { - while(!mStreams.empty()) + if(mStream.get()) { - MyStream *stream = mStreams.front(); - - stream->clearPackets(); - avcodec_close(stream->mCodecCtx); - av_free(stream->mDecodedData); - delete stream; - - mStreams.erase(mStreams.begin()); + mStream->clearPackets(); + avcodec_close(mStream->mCodecCtx); + av_free(mStream->mDecodedData); } + mStream.reset(); + if(mFormatCtx) { AVIOContext* context = mFormatCtx->pb; - av_free(context); - mFormatCtx->pb = NULL; avformat_close_input(&mFormatCtx); + av_free(context); } mFormatCtx = NULL; @@ -331,81 +316,83 @@ std::string FFmpeg_Decoder::getName() void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { - if(mStreams.empty()) + if(!mStream.get()) fail("No audio stream info"); - MyStream *stream = mStreams[0]; - if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8) + if(mStream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8) *type = SampleType_UInt8; - else if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S16) + else if(mStream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S16) *type = SampleType_Int16; else fail(std::string("Unsupported sample format: ")+ - av_get_sample_fmt_name(stream->mCodecCtx->sample_fmt)); + av_get_sample_fmt_name(mStream->mCodecCtx->sample_fmt)); - if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO) + if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO) *chans = ChannelConfig_Mono; - else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO) + else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO) *chans = ChannelConfig_Stereo; - else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_QUAD) + else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_QUAD) *chans = ChannelConfig_Quad; - else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1) + else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1) *chans = ChannelConfig_5point1; - else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1) + else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1) *chans = ChannelConfig_7point1; - else if(stream->mCodecCtx->channel_layout == 0) + else if(mStream->mCodecCtx->channel_layout == 0) { /* Unknown channel layout. Try to guess. */ - if(stream->mCodecCtx->channels == 1) + if(mStream->mCodecCtx->channels == 1) *chans = ChannelConfig_Mono; - else if(stream->mCodecCtx->channels == 2) + else if(mStream->mCodecCtx->channels == 2) *chans = ChannelConfig_Stereo; else { std::stringstream sstr("Unsupported raw channel count: "); - sstr << stream->mCodecCtx->channels; + sstr << mStream->mCodecCtx->channels; fail(sstr.str()); } } else { char str[1024]; - av_get_channel_layout_string(str, sizeof(str), stream->mCodecCtx->channels, - stream->mCodecCtx->channel_layout); + av_get_channel_layout_string(str, sizeof(str), mStream->mCodecCtx->channels, + mStream->mCodecCtx->channel_layout); fail(std::string("Unsupported channel layout: ")+str); } - *samplerate = stream->mCodecCtx->sample_rate; + *samplerate = mStream->mCodecCtx->sample_rate; } size_t FFmpeg_Decoder::read(char *buffer, size_t bytes) { - if(mStreams.empty()) - fail("No audio streams"); + if(!mStream.get()) + fail("No audio stream"); - MyStream *stream = mStreams.front(); - size_t got = stream->readAVAudioData(buffer, bytes); - mSamplesRead += got / av_samples_get_buffer_size(NULL, stream->mCodecCtx->channels, 1, - stream->mCodecCtx->sample_fmt, 1); + size_t got = mStream->readAVAudioData(buffer, bytes); + mSamplesRead += got / mStream->mCodecCtx->channels / + av_get_bytes_per_sample(mStream->mCodecCtx->sample_fmt); return got; } void FFmpeg_Decoder::readAll(std::vector &output) { - if(mStreams.empty()) - fail("No audio streams"); - MyStream *stream = mStreams.front(); + if(!mStream.get()) + fail("No audio stream"); + char *inbuf; size_t got; - - while((inbuf=(char*)stream->getAVAudioData(&got)) != NULL && got > 0) + while((inbuf=(char*)mStream->getAVAudioData(&got)) != NULL && got > 0) + { output.insert(output.end(), inbuf, inbuf+got); + mSamplesRead += got / mStream->mCodecCtx->channels / + av_get_bytes_per_sample(mStream->mCodecCtx->sample_fmt); + } } void FFmpeg_Decoder::rewind() { av_seek_frame(mFormatCtx, -1, 0, 0); - std::for_each(mStreams.begin(), mStreams.end(), std::mem_fun(&MyStream::clearPackets)); + if(mStream.get()) + mStream->clearPackets(); mSamplesRead = 0; } diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index ff63edf07..b7d2e1bb2 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -21,13 +21,14 @@ namespace MWSound { class FFmpeg_Decoder : public Sound_Decoder { + struct MyStream; + AVFormatContext *mFormatCtx; - struct MyStream; - std::vector mStreams; + std::auto_ptr mStream; size_t mSamplesRead; - bool getNextPacket(int streamidx); + bool getNextPacket(); Ogre::DataStreamPtr mDataStream; static int readPacket(void *user_data, uint8_t *buf, int buf_size); From 5f4c33f8960f2d9ba18fe135f01d103b307e1375 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 22:54:54 -0800 Subject: [PATCH 140/916] Only store one packet at a time --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 111 ++++++------------------- 1 file changed, 24 insertions(+), 87 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 205dddd35..70f7682ef 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -15,23 +15,17 @@ static void fail(const std::string &msg) { throw std::runtime_error("FFmpeg exception: "+msg); } -struct PacketList { - AVPacket pkt; - PacketList *next; -}; - struct FFmpeg_Decoder::MyStream { AVCodecContext *mCodecCtx; int mStreamIdx; - PacketList *mPackets; + AVPacket mPacket; char *mDecodedData; size_t mDecodedDataSize; FFmpeg_Decoder *mParent; - void clearPackets(); void *getAVAudioData(size_t *length); size_t readAVAudioData(void *data, size_t length); }; @@ -77,104 +71,47 @@ bool FFmpeg_Decoder::getNextPacket() if(!mStream.get()) return false; - PacketList *packet = (PacketList*)av_malloc(sizeof(*packet)); - packet->next = NULL; - while(av_read_frame(mFormatCtx, &packet->pkt) >= 0) + while(av_read_frame(mFormatCtx, &mStream->mPacket) >= 0) { /* Check if the packet belongs to this stream */ - if(mStream->mStreamIdx == packet->pkt.stream_index) - { - PacketList **last; - - last = &mStream->mPackets; - while(*last != NULL) - last = &(*last)->next; - - *last = packet; + if(mStream->mStreamIdx == mStream->mPacket.stream_index) return true; - } + /* Free the packet and look for another */ - av_free_packet(&packet->pkt); + av_free_packet(&mStream->mPacket); } - av_free(packet); return false; } -void FFmpeg_Decoder::MyStream::clearPackets() -{ - while(mPackets) - { - PacketList *self = mPackets; - mPackets = self->next; - - av_free_packet(&self->pkt); - av_free(self); - } -} - void *FFmpeg_Decoder::MyStream::getAVAudioData(size_t *length) { - int size; - int len; + int size, len; if(length) *length = 0; if(mCodecCtx->codec_type != AVMEDIA_TYPE_AUDIO) return NULL; mDecodedDataSize = 0; + do { + if(mPacket.size == 0 && !mParent->getNextPacket()) + return NULL; -next_packet: - if(!mPackets && !mParent->getNextPacket()) - return NULL; - - /* Decode some data, and check for errors */ - size = AVCODEC_MAX_AUDIO_FRAME_SIZE; - while((len=avcodec_decode_audio3(mCodecCtx, (int16_t*)mDecodedData, &size, - &mPackets->pkt)) == 0) - { - PacketList *self; - - if(size > 0) - break; - - /* Packet went unread and no data was given? Drop it and try the next, - * I guess... */ - self = mPackets; - mPackets = self->next; - - av_free_packet(&self->pkt); - av_free(self); - - if(!mPackets) - goto next_packet; - + /* Decode some data, and check for errors */ size = AVCODEC_MAX_AUDIO_FRAME_SIZE; - } + if((len=avcodec_decode_audio3(mCodecCtx, (int16_t*)mDecodedData, &size, &mPacket)) < 0) + return NULL; - if(len < 0) - return NULL; - - if(len < mPackets->pkt.size) - { /* Move the unread data to the front and clear the end bits */ - int remaining = mPackets->pkt.size - len; - memmove(mPackets->pkt.data, &mPackets->pkt.data[len], remaining); - av_shrink_packet(&mPackets->pkt, remaining); - } - else - { - PacketList *self; - - self = mPackets; - mPackets = self->next; - - av_free_packet(&self->pkt); - av_free(self); - } - - if(size == 0) - goto next_packet; + int remaining = mPacket.size - len; + if(remaining <= 0) + av_free_packet(&mPacket); + else + { + memmove(mPacket.data, &mPacket.data[len], remaining); + av_shrink_packet(&mPacket, remaining); + } + } while(size == 0); /* Set the output buffer size */ mDecodedDataSize = size; @@ -262,7 +199,7 @@ void FFmpeg_Decoder::open(const std::string &fname) std::auto_ptr stream(new MyStream); stream->mCodecCtx = mFormatCtx->streams[audio_idx]->codec; stream->mStreamIdx = audio_idx; - stream->mPackets = NULL; + memset(&stream->mPacket, 0, sizeof(stream->mPacket)); AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id); if(!codec) @@ -292,7 +229,7 @@ void FFmpeg_Decoder::close() { if(mStream.get()) { - mStream->clearPackets(); + av_free_packet(&mStream->mPacket); avcodec_close(mStream->mCodecCtx); av_free(mStream->mDecodedData); } @@ -392,7 +329,7 @@ void FFmpeg_Decoder::rewind() { av_seek_frame(mFormatCtx, -1, 0, 0); if(mStream.get()) - mStream->clearPackets(); + av_free_packet(&mStream->mPacket); mSamplesRead = 0; } From 5fff1c4e47b387aa433d436342909b4ace43626d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 23:22:37 -0800 Subject: [PATCH 141/916] Update the ffmpeg decoder to use avcodec_decode_audio4 --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 82 ++++++++++---------------- 1 file changed, 32 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 70f7682ef..7b6144dd0 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -20,13 +20,14 @@ struct FFmpeg_Decoder::MyStream { int mStreamIdx; AVPacket mPacket; + AVFrame *mFrame; - char *mDecodedData; - size_t mDecodedDataSize; + int mFrameSize; + int mFramePos; FFmpeg_Decoder *mParent; - void *getAVAudioData(size_t *length); + bool getAVAudioData(); size_t readAVAudioData(void *data, size_t length); }; @@ -84,23 +85,20 @@ bool FFmpeg_Decoder::getNextPacket() return false; } -void *FFmpeg_Decoder::MyStream::getAVAudioData(size_t *length) +bool FFmpeg_Decoder::MyStream::getAVAudioData() { - int size, len; + int got_frame, len; - if(length) *length = 0; if(mCodecCtx->codec_type != AVMEDIA_TYPE_AUDIO) - return NULL; + return false; - mDecodedDataSize = 0; do { if(mPacket.size == 0 && !mParent->getNextPacket()) - return NULL; + return false; /* Decode some data, and check for errors */ - size = AVCODEC_MAX_AUDIO_FRAME_SIZE; - if((len=avcodec_decode_audio3(mCodecCtx, (int16_t*)mDecodedData, &size, &mPacket)) < 0) - return NULL; + if((len=avcodec_decode_audio4(mCodecCtx, mFrame, &got_frame, &mPacket)) < 0) + return false; /* Move the unread data to the front and clear the end bits */ int remaining = mPacket.size - len; @@ -111,13 +109,9 @@ void *FFmpeg_Decoder::MyStream::getAVAudioData(size_t *length) memmove(mPacket.data, &mPacket.data[len], remaining); av_shrink_packet(&mPacket, remaining); } - } while(size == 0); + } while(got_frame == 0 || mFrame->nb_samples == 0); - /* Set the output buffer size */ - mDecodedDataSize = size; - if(length) *length = mDecodedDataSize; - - return mDecodedData; + return true; } size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length) @@ -127,34 +121,24 @@ size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length) while(dec < length) { /* If there's no decoded data, find some */ - if(mDecodedDataSize == 0) + if(mFramePos >= mFrameSize) { - if(getAVAudioData(NULL) == NULL) + if(!getAVAudioData()) break; + mFramePos = 0; + mFrameSize = mFrame->nb_samples * mCodecCtx->channels * + av_get_bytes_per_sample(mCodecCtx->sample_fmt); } - if(mDecodedDataSize > 0) - { - /* Get the amount of bytes remaining to be written, and clamp to - * the amount of decoded data we have */ - size_t rem = length-dec; - if(rem > mDecodedDataSize) - rem = mDecodedDataSize; + /* Get the amount of bytes remaining to be written, and clamp to + * the amount of decoded data we have */ + size_t rem = std::min(length-dec, mFrameSize-mFramePos); - /* Copy the data to the app's buffer and increment */ - if(data != NULL) - { - memcpy(data, mDecodedData, rem); - data = (char*)data + rem; - } - dec += rem; - - /* If there's any decoded data left, move it to the front of the - * buffer for next time */ - if(rem < mDecodedDataSize) - memmove(mDecodedData, &mDecodedData[rem], mDecodedDataSize - rem); - mDecodedDataSize -= rem; - } + /* Copy the data to the app's buffer and increment */ + memcpy(data, mFrame->data[0]+mFramePos, rem); + data = (char*)data + rem; + dec += rem; + mFramePos += rem; } /* Return the number of bytes we were able to get */ @@ -162,7 +146,6 @@ size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length) } - void FFmpeg_Decoder::open(const std::string &fname) { close(); @@ -211,8 +194,7 @@ void FFmpeg_Decoder::open(const std::string &fname) if(avcodec_open2(stream->mCodecCtx, codec, NULL) < 0) fail("Failed to open audio codec " + std::string(codec->long_name)); - stream->mDecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); - stream->mDecodedDataSize = 0; + stream->mFrame = avcodec_alloc_frame(); stream->mParent = this; mStream = stream; @@ -231,7 +213,7 @@ void FFmpeg_Decoder::close() { av_free_packet(&mStream->mPacket); avcodec_close(mStream->mCodecCtx); - av_free(mStream->mDecodedData); + av_free(mStream->mFrame); } mStream.reset(); @@ -315,13 +297,13 @@ void FFmpeg_Decoder::readAll(std::vector &output) if(!mStream.get()) fail("No audio stream"); - char *inbuf; - size_t got; - while((inbuf=(char*)mStream->getAVAudioData(&got)) != NULL && got > 0) + while(mStream->getAVAudioData()) { + size_t got = mStream->mFrame->nb_samples * mStream->mCodecCtx->channels * + av_get_bytes_per_sample(mStream->mCodecCtx->sample_fmt); + const char *inbuf = reinterpret_cast(mStream->mFrame->data[0]); output.insert(output.end(), inbuf, inbuf+got); - mSamplesRead += got / mStream->mCodecCtx->channels / - av_get_bytes_per_sample(mStream->mCodecCtx->sample_fmt); + mSamplesRead += mStream->mFrame->nb_samples; } } From 1a771ae67150a2ed4539cdb44db40f0e4fe8097c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 15 Dec 2012 23:46:32 -0800 Subject: [PATCH 142/916] Merge the stream struct into the parent decoder --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 142 +++++++++++-------------- apps/openmw/mwsound/ffmpeg_decoder.hpp | 13 ++- 2 files changed, 71 insertions(+), 84 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 7b6144dd0..e0f071568 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -15,23 +15,6 @@ static void fail(const std::string &msg) { throw std::runtime_error("FFmpeg exception: "+msg); } -struct FFmpeg_Decoder::MyStream { - AVCodecContext *mCodecCtx; - int mStreamIdx; - - AVPacket mPacket; - AVFrame *mFrame; - - int mFrameSize; - int mFramePos; - - FFmpeg_Decoder *mParent; - - bool getAVAudioData(); - size_t readAVAudioData(void *data, size_t length); -}; - - int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) { Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; @@ -69,35 +52,36 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) * handle for. */ bool FFmpeg_Decoder::getNextPacket() { - if(!mStream.get()) + if(!mStream) return false; - while(av_read_frame(mFormatCtx, &mStream->mPacket) >= 0) + int stream_idx = mStream - mFormatCtx->streams; + while(av_read_frame(mFormatCtx, &mPacket) >= 0) { /* Check if the packet belongs to this stream */ - if(mStream->mStreamIdx == mStream->mPacket.stream_index) + if(stream_idx == mPacket.stream_index) return true; /* Free the packet and look for another */ - av_free_packet(&mStream->mPacket); + av_free_packet(&mPacket); } return false; } -bool FFmpeg_Decoder::MyStream::getAVAudioData() +bool FFmpeg_Decoder::getAVAudioData() { int got_frame, len; - if(mCodecCtx->codec_type != AVMEDIA_TYPE_AUDIO) + if((*mStream)->codec->codec_type != AVMEDIA_TYPE_AUDIO) return false; do { - if(mPacket.size == 0 && !mParent->getNextPacket()) + if(mPacket.size == 0 && !getNextPacket()) return false; /* Decode some data, and check for errors */ - if((len=avcodec_decode_audio4(mCodecCtx, mFrame, &got_frame, &mPacket)) < 0) + if((len=avcodec_decode_audio4((*mStream)->codec, mFrame, &got_frame, &mPacket)) < 0) return false; /* Move the unread data to the front and clear the end bits */ @@ -114,7 +98,7 @@ bool FFmpeg_Decoder::MyStream::getAVAudioData() return true; } -size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length) +size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) { size_t dec = 0; @@ -126,8 +110,8 @@ size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length) if(!getAVAudioData()) break; mFramePos = 0; - mFrameSize = mFrame->nb_samples * mCodecCtx->channels * - av_get_bytes_per_sample(mCodecCtx->sample_fmt); + mFrameSize = mFrame->nb_samples * (*mStream)->codec->channels * + av_get_bytes_per_sample((*mStream)->codec->sample_fmt); } /* Get the amount of bytes remaining to be written, and clamp to @@ -167,55 +151,46 @@ void FFmpeg_Decoder::open(const std::string &fname) if(avformat_find_stream_info(mFormatCtx, NULL) < 0) fail("Failed to find stream info in "+fname); - int audio_idx = -1; for(size_t j = 0;j < mFormatCtx->nb_streams;j++) { if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - audio_idx = j; + mStream = &mFormatCtx->streams[j]; break; } } - if(audio_idx == -1) + if(!mStream) fail("No audio streams in "+fname); - std::auto_ptr stream(new MyStream); - stream->mCodecCtx = mFormatCtx->streams[audio_idx]->codec; - stream->mStreamIdx = audio_idx; - memset(&stream->mPacket, 0, sizeof(stream->mPacket)); + memset(&mPacket, 0, sizeof(mPacket)); - AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id); + AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id); if(!codec) { std::stringstream ss("No codec found for id "); - ss << stream->mCodecCtx->codec_id; + ss << (*mStream)->codec->codec_id; fail(ss.str()); } - if(avcodec_open2(stream->mCodecCtx, codec, NULL) < 0) + if(avcodec_open2((*mStream)->codec, codec, NULL) < 0) fail("Failed to open audio codec " + std::string(codec->long_name)); - stream->mFrame = avcodec_alloc_frame(); - - stream->mParent = this; - mStream = stream; + mFrame = avcodec_alloc_frame(); } catch(std::exception &e) { avformat_close_input(&mFormatCtx); - mFormatCtx = NULL; throw; } } void FFmpeg_Decoder::close() { - if(mStream.get()) - { - av_free_packet(&mStream->mPacket); - avcodec_close(mStream->mCodecCtx); - av_free(mStream->mFrame); - } - mStream.reset(); + if(mStream) + avcodec_close((*mStream)->codec); + mStream = NULL; + + av_free_packet(&mPacket); + av_freep(&mFrame); if(mFormatCtx) { @@ -223,7 +198,6 @@ void FFmpeg_Decoder::close() avformat_close_input(&mFormatCtx); av_free(context); } - mFormatCtx = NULL; mDataStream.setNull(); } @@ -235,83 +209,82 @@ std::string FFmpeg_Decoder::getName() void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { - if(!mStream.get()) + if(!mStream) fail("No audio stream info"); - if(mStream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8) + if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_U8) *type = SampleType_UInt8; - else if(mStream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S16) + else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = SampleType_Int16; else fail(std::string("Unsupported sample format: ")+ - av_get_sample_fmt_name(mStream->mCodecCtx->sample_fmt)); + av_get_sample_fmt_name((*mStream)->codec->sample_fmt)); - if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO) + if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_MONO) *chans = ChannelConfig_Mono; - else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO) + else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_STEREO) *chans = ChannelConfig_Stereo; - else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_QUAD) + else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_QUAD) *chans = ChannelConfig_Quad; - else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_5POINT1) + else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_5POINT1) *chans = ChannelConfig_5point1; - else if(mStream->mCodecCtx->channel_layout == AV_CH_LAYOUT_7POINT1) + else if((*mStream)->codec->channel_layout == AV_CH_LAYOUT_7POINT1) *chans = ChannelConfig_7point1; - else if(mStream->mCodecCtx->channel_layout == 0) + else if((*mStream)->codec->channel_layout == 0) { /* Unknown channel layout. Try to guess. */ - if(mStream->mCodecCtx->channels == 1) + if((*mStream)->codec->channels == 1) *chans = ChannelConfig_Mono; - else if(mStream->mCodecCtx->channels == 2) + else if((*mStream)->codec->channels == 2) *chans = ChannelConfig_Stereo; else { std::stringstream sstr("Unsupported raw channel count: "); - sstr << mStream->mCodecCtx->channels; + sstr << (*mStream)->codec->channels; fail(sstr.str()); } } else { char str[1024]; - av_get_channel_layout_string(str, sizeof(str), mStream->mCodecCtx->channels, - mStream->mCodecCtx->channel_layout); + av_get_channel_layout_string(str, sizeof(str), (*mStream)->codec->channels, + (*mStream)->codec->channel_layout); fail(std::string("Unsupported channel layout: ")+str); } - *samplerate = mStream->mCodecCtx->sample_rate; + *samplerate = (*mStream)->codec->sample_rate; } size_t FFmpeg_Decoder::read(char *buffer, size_t bytes) { - if(!mStream.get()) + if(!mStream) fail("No audio stream"); - size_t got = mStream->readAVAudioData(buffer, bytes); - mSamplesRead += got / mStream->mCodecCtx->channels / - av_get_bytes_per_sample(mStream->mCodecCtx->sample_fmt); + size_t got = readAVAudioData(buffer, bytes); + mSamplesRead += got / (*mStream)->codec->channels / + av_get_bytes_per_sample((*mStream)->codec->sample_fmt); return got; } void FFmpeg_Decoder::readAll(std::vector &output) { - if(!mStream.get()) + if(!mStream) fail("No audio stream"); - while(mStream->getAVAudioData()) + while(getAVAudioData()) { - size_t got = mStream->mFrame->nb_samples * mStream->mCodecCtx->channels * - av_get_bytes_per_sample(mStream->mCodecCtx->sample_fmt); - const char *inbuf = reinterpret_cast(mStream->mFrame->data[0]); + size_t got = mFrame->nb_samples * (*mStream)->codec->channels * + av_get_bytes_per_sample((*mStream)->codec->sample_fmt); + const char *inbuf = reinterpret_cast(mFrame->data[0]); output.insert(output.end(), inbuf, inbuf+got); - mSamplesRead += mStream->mFrame->nb_samples; + mSamplesRead += mFrame->nb_samples; } } void FFmpeg_Decoder::rewind() { av_seek_frame(mFormatCtx, -1, 0, 0); - if(mStream.get()) - av_free_packet(&mStream->mPacket); + av_free_packet(&mPacket); mSamplesRead = 0; } @@ -320,12 +293,19 @@ size_t FFmpeg_Decoder::getSampleOffset() return mSamplesRead; } -FFmpeg_Decoder::FFmpeg_Decoder() : mFormatCtx(NULL), mSamplesRead(0) +FFmpeg_Decoder::FFmpeg_Decoder() + : mFormatCtx(NULL) + , mStream(NULL) + , mFrame(NULL) + , mFrameSize(0) + , mFramePos(0) + , mSamplesRead(0) { - static bool done_init = false; + memset(&mPacket, 0, sizeof(mPacket)); /* We need to make sure ffmpeg is initialized. Optionally silence warning * output from the lib */ + static bool done_init = false; if(!done_init) { av_register_all(); diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index b7d2e1bb2..dbd4f5adc 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -21,11 +21,15 @@ namespace MWSound { class FFmpeg_Decoder : public Sound_Decoder { - struct MyStream; - AVFormatContext *mFormatCtx; + AVStream **mStream; + + AVPacket mPacket; + AVFrame *mFrame; + + int mFrameSize; + int mFramePos; - std::auto_ptr mStream; size_t mSamplesRead; bool getNextPacket(); @@ -35,6 +39,9 @@ namespace MWSound static int writePacket(void *user_data, uint8_t *buf, int buf_size); static int64_t seek(void *user_data, int64_t offset, int whence); + bool getAVAudioData(); + size_t readAVAudioData(void *data, size_t length); + virtual void open(const std::string &fname); virtual void close(); From 4561c22e2b5f55253ea179907f7dfe62aa475faf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 00:07:56 -0800 Subject: [PATCH 143/916] More fixes for the audio clock The audio_clock for the decoder represents the end of the current packet, so it needs to be adjusted back to match the position that's actually going to be read next. --- apps/openmw/mwrender/videoplayer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 0165d9855..d57295f65 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -416,7 +416,7 @@ public: break; } - mFramePos = std::min(static_cast(mFrameSize), sample_skip); + mFramePos = std::min(mFrameSize, sample_skip); sample_skip -= mFramePos; } @@ -471,7 +471,9 @@ public: size_t getSampleOffset() { - return (size_t)(is->audio_clock*is->audio_st->codec->sample_rate); + ssize_t clock_delay = (mFrameSize-mFramePos) / is->audio_st->codec->channels / + av_get_bytes_per_sample(is->audio_st->codec->sample_fmt); + return (size_t)(is->audio_clock*is->audio_st->codec->sample_rate) - clock_delay; } }; From 0edc87825d1ea553a9ec8f7d990945608c6e8a09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 01:17:58 -0800 Subject: [PATCH 144/916] Move audio_clock to the decoder where it's used --- apps/openmw/mwrender/videoplayer.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index d57295f65..cac25713a 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -58,11 +58,10 @@ struct VideoPicture { struct VideoState { VideoState() : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock_base(0), - audio_clock(0), audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), - audio_diff_threshold(0), audio_diff_avg_count(0), frame_last_pts(0), - frame_last_delay(0), video_clock(0), video_st(NULL), rgbaFrame(NULL), pictq_size(0), - pictq_rindex(0), pictq_windex(0), quit(false), refresh(0), format_ctx(0), - sws_context(NULL), display_ready(0) + audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), audio_diff_threshold(0), + audio_diff_avg_count(0), frame_last_pts(0), frame_last_delay(0), video_clock(0), + video_st(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), + quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) { } ~VideoState() @@ -114,7 +113,6 @@ struct VideoState { int av_sync_type; uint64_t external_clock_base; - double audio_clock; AVStream *audio_st; PacketQueue audioq; double audio_diff_cum; /* used for AV difference average computation */ @@ -256,6 +254,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder ssize_t mFramePos; ssize_t mFrameSize; + double audio_clock; + /* Add or subtract samples to get a better sync, return number of bytes to * skip (negative means to duplicate). */ int synchronize_audio() @@ -310,8 +310,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder if(!got_frame || frame->nb_samples <= 0) continue; - is->audio_clock += (double)frame->nb_samples / - (double)is->audio_st->codec->sample_rate; + this->audio_clock += (double)frame->nb_samples / + (double)is->audio_st->codec->sample_rate; /* We have data, return it and come back for more later */ return frame->nb_samples * av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * @@ -328,7 +328,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder /* if update, update the audio clock w/pts */ if((uint64_t)pkt->pts != AV_NOPTS_VALUE) - is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; + this->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; } } @@ -348,6 +348,7 @@ public: , mFrame(avcodec_alloc_frame()) , mFramePos(0) , mFrameSize(0) + , audio_clock(0.0) { } virtual ~MovieAudioDecoder() { @@ -473,7 +474,7 @@ public: { ssize_t clock_delay = (mFrameSize-mFramePos) / is->audio_st->codec->channels / av_get_bytes_per_sample(is->audio_st->codec->sample_fmt); - return (size_t)(is->audio_clock*is->audio_st->codec->sample_rate) - clock_delay; + return (size_t)(this->audio_clock*is->audio_st->codec->sample_rate) - clock_delay; } }; From e9d833be036879b650911bf65a9ae1a582eed5bb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 01:56:52 -0800 Subject: [PATCH 145/916] Use the packet pts to calculate the decoder sample offset --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 27 ++++++++++++++------------ apps/openmw/mwsound/ffmpeg_decoder.hpp | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index e0f071568..261a86ca6 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -60,7 +60,11 @@ bool FFmpeg_Decoder::getNextPacket() { /* Check if the packet belongs to this stream */ if(stream_idx == mPacket.stream_index) + { + if((uint64_t)mPacket.pts != AV_NOPTS_VALUE) + mNextPts = av_q2d((*mStream)->time_base)*mPacket.pts; return true; + } /* Free the packet and look for another */ av_free_packet(&mPacket); @@ -94,6 +98,7 @@ bool FFmpeg_Decoder::getAVAudioData() av_shrink_packet(&mPacket, remaining); } } while(got_frame == 0 || mFrame->nb_samples == 0); + mNextPts += (double)mFrame->nb_samples / (double)(*mStream)->codec->sample_rate; return true; } @@ -162,8 +167,6 @@ void FFmpeg_Decoder::open(const std::string &fname) if(!mStream) fail("No audio streams in "+fname); - memset(&mPacket, 0, sizeof(mPacket)); - AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id); if(!codec) { @@ -259,11 +262,7 @@ size_t FFmpeg_Decoder::read(char *buffer, size_t bytes) { if(!mStream) fail("No audio stream"); - - size_t got = readAVAudioData(buffer, bytes); - mSamplesRead += got / (*mStream)->codec->channels / - av_get_bytes_per_sample((*mStream)->codec->sample_fmt); - return got; + return readAVAudioData(buffer, bytes); } void FFmpeg_Decoder::readAll(std::vector &output) @@ -277,20 +276,24 @@ void FFmpeg_Decoder::readAll(std::vector &output) av_get_bytes_per_sample((*mStream)->codec->sample_fmt); const char *inbuf = reinterpret_cast(mFrame->data[0]); output.insert(output.end(), inbuf, inbuf+got); - mSamplesRead += mFrame->nb_samples; } } void FFmpeg_Decoder::rewind() { - av_seek_frame(mFormatCtx, -1, 0, 0); + int stream_idx = mStream - mFormatCtx->streams; + if(av_seek_frame(mFormatCtx, stream_idx, 0, 0) < 0) + fail("Failed to seek in audio stream"); av_free_packet(&mPacket); - mSamplesRead = 0; + mFrameSize = mFramePos = 0; + mNextPts = 0.0; } size_t FFmpeg_Decoder::getSampleOffset() { - return mSamplesRead; + int delay = (mFrameSize-mFramePos) / (*mStream)->codec->channels / + av_get_bytes_per_sample((*mStream)->codec->sample_fmt); + return (int)(mNextPts*(*mStream)->codec->sample_rate) - delay; } FFmpeg_Decoder::FFmpeg_Decoder() @@ -299,7 +302,7 @@ FFmpeg_Decoder::FFmpeg_Decoder() , mFrame(NULL) , mFrameSize(0) , mFramePos(0) - , mSamplesRead(0) + , mNextPts(0.0) { memset(&mPacket, 0, sizeof(mPacket)); diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index dbd4f5adc..32b2797ed 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -30,7 +30,7 @@ namespace MWSound int mFrameSize; int mFramePos; - size_t mSamplesRead; + double mNextPts; bool getNextPacket(); From 3f6d36c7127bd5cb6144a56497ae5fe3daeaf663 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 02:19:19 -0800 Subject: [PATCH 146/916] Avoid double-setting the material texture --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index cac25713a..c5976222f 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -949,7 +949,7 @@ VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) mVideoMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); - mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState()->setTextureName("black.png"); + mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(); } mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); From dd20db5dc2ff26eda2b5dad4274eac3228b7310a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 03:05:44 -0800 Subject: [PATCH 147/916] Remove the stream indices from the VideoState --- apps/openmw/mwrender/videoplayer.cpp | 180 +++++++++++++-------------- 1 file changed, 87 insertions(+), 93 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index c5976222f..81eba2417 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -57,11 +57,14 @@ struct VideoPicture { struct VideoState { VideoState() - : videoStream(-1), audioStream(-1), av_sync_type(0), external_clock_base(0), - audio_st(NULL), audio_diff_cum(0), audio_diff_avg_coef(0), audio_diff_threshold(0), - audio_diff_avg_count(0), frame_last_pts(0), frame_last_delay(0), video_clock(0), - video_st(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0), - quit(false), refresh(0), format_ctx(0), sws_context(NULL), display_ready(0) + : format_ctx(NULL), av_sync_type(AV_SYNC_DEFAULT) + , external_clock_base(0.0) + , audio_st(NULL), audio_diff_cum(0.0), audio_diff_avg_coef(0.0), + audio_diff_threshold(0.0), audio_diff_avg_count(0) + , video_st(NULL), frame_last_pts(0.0), frame_last_delay(0.0), + video_clock(0.0), sws_context(NULL), rgbaFrame(NULL), pictq_size(0), + pictq_rindex(0), pictq_windex(0) + , refresh_rate_ms(10), refresh(false), quit(false), display_ready(false) { } ~VideoState() @@ -108,38 +111,33 @@ struct VideoState { static int64_t OgreResource_Seek(void *user_data, int64_t offset, int whence); - int videoStream, audioStream; + Ogre::DataStreamPtr stream; + AVFormatContext* format_ctx; int av_sync_type; uint64_t external_clock_base; - AVStream *audio_st; + AVStream** audio_st; PacketQueue audioq; double audio_diff_cum; /* used for AV difference average computation */ double audio_diff_avg_coef; double audio_diff_threshold; int audio_diff_avg_count; + MWBase::SoundPtr AudioTrack; + AVStream** video_st; double frame_last_pts; double frame_last_delay; double video_clock; ///audio_diff_cum * (1.0 - is->audio_diff_avg_coef); if(fabs(avg_diff) >= is->audio_diff_threshold) { - int n = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * - is->audio_st->codec->channels; - sample_skip = ((int)(diff * is->audio_st->codec->sample_rate) * n); + int n = av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt) * + (*is->audio_st)->codec->channels; + sample_skip = ((int)(diff * (*is->audio_st)->codec->sample_rate) * n); } } @@ -295,7 +292,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder { int len1, got_frame; - len1 = avcodec_decode_audio4(is->audio_st->codec, frame, &got_frame, pkt); + len1 = avcodec_decode_audio4((*is->audio_st)->codec, frame, &got_frame, pkt); if(len1 < 0) break; if(len1 <= pkt->size) @@ -311,11 +308,11 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder continue; this->audio_clock += (double)frame->nb_samples / - (double)is->audio_st->codec->sample_rate; + (double)(*is->audio_st)->codec->sample_rate; /* We have data, return it and come back for more later */ - return frame->nb_samples * av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * - is->audio_st->codec->channels; + return frame->nb_samples * av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt) * + (*is->audio_st)->codec->channels; } av_free_packet(pkt); @@ -328,7 +325,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder /* if update, update the audio clock w/pts */ if((uint64_t)pkt->pts != AV_NOPTS_VALUE) - this->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts; + this->audio_clock = av_q2d((*is->audio_st)->time_base)*pkt->pts; } } @@ -357,47 +354,47 @@ public: void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) { - if(is->audio_st->codec->sample_fmt == AV_SAMPLE_FMT_U8) + if((*is->audio_st)->codec->sample_fmt == AV_SAMPLE_FMT_U8) *type = MWSound::SampleType_UInt8; - else if(is->audio_st->codec->sample_fmt == AV_SAMPLE_FMT_S16) + else if((*is->audio_st)->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = MWSound::SampleType_Int16; else fail(std::string("Unsupported sample format: ")+ - av_get_sample_fmt_name(is->audio_st->codec->sample_fmt)); + av_get_sample_fmt_name((*is->audio_st)->codec->sample_fmt)); - if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_MONO) + if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_MONO) *chans = MWSound::ChannelConfig_Mono; - else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_STEREO) + else if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_STEREO) *chans = MWSound::ChannelConfig_Stereo; - else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_QUAD) + else if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_QUAD) *chans = MWSound::ChannelConfig_Quad; - else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_5POINT1) + else if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_5POINT1) *chans = MWSound::ChannelConfig_5point1; - else if(is->audio_st->codec->channel_layout == AV_CH_LAYOUT_7POINT1) + else if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_7POINT1) *chans = MWSound::ChannelConfig_7point1; - else if(is->audio_st->codec->channel_layout == 0) + else if((*is->audio_st)->codec->channel_layout == 0) { /* Unknown channel layout. Try to guess. */ - if(is->audio_st->codec->channels == 1) + if((*is->audio_st)->codec->channels == 1) *chans = MWSound::ChannelConfig_Mono; - else if(is->audio_st->codec->channels == 2) + else if((*is->audio_st)->codec->channels == 2) *chans = MWSound::ChannelConfig_Stereo; else { std::stringstream sstr("Unsupported raw channel count: "); - sstr << is->audio_st->codec->channels; + sstr << (*is->audio_st)->codec->channels; fail(sstr.str()); } } else { char str[1024]; - av_get_channel_layout_string(str, sizeof(str), is->audio_st->codec->channels, - is->audio_st->codec->channel_layout); + av_get_channel_layout_string(str, sizeof(str), (*is->audio_st)->codec->channels, + (*is->audio_st)->codec->channel_layout); fail(std::string("Unsupported channel layout: ")+str); } - *samplerate = is->audio_st->codec->sample_rate; + *samplerate = (*is->audio_st)->codec->sample_rate; } size_t read(char *stream, size_t len) @@ -431,8 +428,8 @@ public: { len1 = std::min(len1, -mFramePos); - int n = av_get_bytes_per_sample(is->audio_st->codec->sample_fmt) * - is->audio_st->codec->channels; + int n = av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt) * + (*is->audio_st)->codec->channels; /* add samples by copying the first sample*/ if(n == 1) @@ -472,9 +469,9 @@ public: size_t getSampleOffset() { - ssize_t clock_delay = (mFrameSize-mFramePos) / is->audio_st->codec->channels / - av_get_bytes_per_sample(is->audio_st->codec->sample_fmt); - return (size_t)(this->audio_clock*is->audio_st->codec->sample_rate) - clock_delay; + ssize_t clock_delay = (mFrameSize-mFramePos) / (*is->audio_st)->codec->channels / + av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt); + return (size_t)(this->audio_clock*(*is->audio_st)->codec->sample_rate) - clock_delay; } }; @@ -527,26 +524,26 @@ void VideoState::video_display() { VideoPicture *vp = &this->pictq[this->pictq_rindex]; - if(this->video_st->codec->width != 0 && this->video_st->codec->height != 0) + if((*this->video_st)->codec->width != 0 && (*this->video_st)->codec->height != 0) { Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("VideoTexture"); - if(texture.isNull () || static_cast(texture->getWidth()) != this->video_st->codec->width - || static_cast(texture->getHeight()) != this->video_st->codec->height) + if(texture.isNull() || static_cast(texture->getWidth()) != (*this->video_st)->codec->width + || static_cast(texture->getHeight()) != (*this->video_st)->codec->height) { Ogre::TextureManager::getSingleton ().remove ("VideoTexture"); texture = Ogre::TextureManager::getSingleton().createManual( "VideoTexture", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, - this->video_st->codec->width, this->video_st->codec->height, + (*this->video_st)->codec->width, (*this->video_st)->codec->height, 0, Ogre::PF_BYTE_RGBA, Ogre::TU_DYNAMIC_WRITE_ONLY_DISCARDABLE); } - Ogre::PixelBox pb(this->video_st->codec->width, this->video_st->codec->height, 1, Ogre::PF_BYTE_RGBA, &vp->data[0]); + Ogre::PixelBox pb((*this->video_st)->codec->width, (*this->video_st)->codec->height, 1, Ogre::PF_BYTE_RGBA, &vp->data[0]); Ogre::HardwarePixelBufferSharedPtr buffer = texture->getBuffer(); buffer->blitFromMemory(pb); - this->display_ready = 1; + this->display_ready = true; } } @@ -617,9 +614,9 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) // Convert the image into RGBA format for Ogre if(this->sws_context == NULL) { - int w = this->video_st->codec->width; - int h = this->video_st->codec->height; - this->sws_context = sws_getContext(w, h, this->video_st->codec->pix_fmt, + int w = (*this->video_st)->codec->width; + int h = (*this->video_st)->codec->height; + this->sws_context = sws_getContext(w, h, (*this->video_st)->codec->pix_fmt, w, h, PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); if(this->sws_context == NULL) @@ -627,11 +624,11 @@ int VideoState::queue_picture(AVFrame *pFrame, double pts) } vp->pts = pts; - vp->data.resize(this->video_st->codec->width * this->video_st->codec->height * 4); + vp->data.resize((*this->video_st)->codec->width * (*this->video_st)->codec->height * 4); uint8_t *dst = &vp->data[0]; sws_scale(this->sws_context, pFrame->data, pFrame->linesize, - 0, this->video_st->codec->height, &dst, this->rgbaFrame->linesize); + 0, (*this->video_st)->codec->height, &dst, this->rgbaFrame->linesize); // now we inform our display thread that we have a pic ready this->pictq_windex = (this->pictq_windex+1) % VIDEO_PICTURE_QUEUE_SIZE; @@ -653,7 +650,7 @@ double VideoState::synchronize_video(AVFrame *src_frame, double pts) pts = this->video_clock; /* update the video clock */ - frame_delay = av_q2d(this->video_st->codec->time_base); + frame_delay = av_q2d((*this->video_st)->codec->time_base); /* if we are repeating a frame, adjust clock accordingly */ frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); @@ -693,14 +690,14 @@ void VideoState::video_thread_loop(VideoState *self) pFrame = avcodec_alloc_frame(); self->rgbaFrame = avcodec_alloc_frame(); - avpicture_alloc((AVPicture*)self->rgbaFrame, PIX_FMT_RGBA, self->video_st->codec->width, self->video_st->codec->height); + avpicture_alloc((AVPicture*)self->rgbaFrame, PIX_FMT_RGBA, (*self->video_st)->codec->width, (*self->video_st)->codec->height); while(self->videoq.get(packet, self) >= 0) { // Save global pts to be stored in pFrame global_video_pkt_pts = packet->pts; // Decode video frame - if(avcodec_decode_video2(self->video_st->codec, pFrame, &frameFinished, packet) < 0) + if(avcodec_decode_video2((*self->video_st)->codec, pFrame, &frameFinished, packet) < 0) throw std::runtime_error("Error decoding video frame"); pts = 0; @@ -708,7 +705,7 @@ void VideoState::video_thread_loop(VideoState *self) pts = packet->dts; else if(pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE) pts = *(uint64_t*)pFrame->opaque; - pts *= av_q2d(self->video_st->time_base); + pts *= av_q2d((*self->video_st)->time_base); av_free_packet(packet); @@ -734,14 +731,14 @@ void VideoState::decode_thread_loop(VideoState *self) try { - if(self->videoStream < 0 && self->audioStream < 0) + if(!self->video_st && !self->audio_st < 0) throw std::runtime_error("No streams to decode"); // main decode loop while(!self->quit) { - if((self->audioStream >= 0 && self->audioq.size > MAX_AUDIOQ_SIZE) || - (self->videoStream >= 0 && self->videoq.size > MAX_VIDEOQ_SIZE)) + if((self->audio_st >= 0 && self->audioq.size > MAX_AUDIOQ_SIZE) || + (self->video_st >= 0 && self->videoq.size > MAX_VIDEOQ_SIZE)) { boost::this_thread::sleep(boost::posix_time::milliseconds(10)); continue; @@ -751,9 +748,9 @@ void VideoState::decode_thread_loop(VideoState *self) break; // Is this a packet from the video stream? - if(packet->stream_index == self->videoStream) + if(self->video_st && packet->stream_index == self->video_st-pFormatCtx->streams) self->videoq.put(packet); - else if(packet->stream_index == self->audioStream) + else if(self->audio_st && packet->stream_index == self->audio_st-pFormatCtx->streams) self->audioq.put(packet); else av_free_packet(packet); @@ -774,7 +771,7 @@ void VideoState::decode_thread_loop(VideoState *self) std::cerr << "An error occured playing the video: " << e.getFullDescription () << std::endl; } - self->quit = 1; + self->quit = true; } @@ -799,8 +796,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) switch(codecCtx->codec_type) { case AVMEDIA_TYPE_AUDIO: - this->audioStream = stream_index; - this->audio_st = pFormatCtx->streams[stream_index]; + this->audio_st = pFormatCtx->streams + stream_index; /* averaging filter for audio sync */ this->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); @@ -812,16 +808,14 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) this->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); if(!this->AudioTrack) { - this->audioStream = -1; - avcodec_close(this->audio_st->codec); + avcodec_close((*this->audio_st)->codec); this->audio_st = NULL; return -1; } break; case AVMEDIA_TYPE_VIDEO: - this->videoStream = stream_index; - this->video_st = pFormatCtx->streams[stream_index]; + this->video_st = pFormatCtx->streams + stream_index; this->frame_last_delay = 40e-3; @@ -847,11 +841,9 @@ void VideoState::init(const std::string& resourceName) unsigned int i; this->av_sync_type = AV_SYNC_DEFAULT; - this->videoStream = -1; - this->audioStream = -1; this->refresh_rate_ms = 10; this->refresh = false; - this->quit = 0; + this->quit = false; this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); if(this->stream.isNull()) @@ -899,12 +891,12 @@ void VideoState::init(const std::string& resourceName) } catch(std::runtime_error& e) { - this->quit = 1; + this->quit = true; throw; } catch(Ogre::Exception& e) { - this->quit = 1; + this->quit = true; throw; } } @@ -918,13 +910,16 @@ void VideoState::deinit() this->video_thread.join(); this->refresh_thread.join(); - if(this->audioStream >= 0) - avcodec_close(this->audio_st->codec); - if(this->videoStream >= 0) - avcodec_close(this->video_st->codec); + if(this->audio_st) + avcodec_close((*this->audio_st)->codec); + this->audio_st = NULL; + if(this->video_st) + avcodec_close((*this->video_st)->codec); + this->video_st = NULL; if(this->sws_context) sws_freeContext(this->sws_context); + this->sws_context = NULL; if(this->format_ctx) { @@ -1012,6 +1007,7 @@ void VideoPlayer::playVideo(const std::string &resourceName) mRectangle->setVisible(true); mBackgroundRectangle->setVisible(true); + mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Video); @@ -1029,8 +1025,6 @@ void VideoPlayer::playVideo(const std::string &resourceName) mState = new VideoState; mState->init(resourceName); - - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); } void VideoPlayer::update () @@ -1048,23 +1042,23 @@ void VideoPlayer::update () mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("VideoTexture"); // Correct aspect ratio by adding black bars - double videoaspect = static_cast(mState->video_st->codec->width) / mState->video_st->codec->height; - - if (av_q2d(mState->video_st->codec->sample_aspect_ratio) != 0) - videoaspect *= av_q2d(mState->video_st->codec->sample_aspect_ratio); + double videoaspect = av_q2d((*mState->video_st)->codec->sample_aspect_ratio); + if(videoaspect == 0.0) + videoaspect = 1.0; + videoaspect *= static_cast((*mState->video_st)->codec->width) / (*mState->video_st)->codec->height; double screenaspect = static_cast(mWidth) / mHeight; double aspect_correction = videoaspect / screenaspect; - mRectangle->setCorners (std::max(-1.0, -1.0 * aspect_correction), std::min(1.0, 1.0 / aspect_correction), - std::min(1.0, 1.0 * aspect_correction), std::max(-1.0, -1.0 / aspect_correction)); + mRectangle->setCorners(std::max(-1.0, -1.0 * aspect_correction), std::min( 1.0, 1.0 / aspect_correction), + std::min( 1.0, 1.0 * aspect_correction), std::max(-1.0, -1.0 / aspect_correction)); } } } void VideoPlayer::close() { - mState->quit = 1; + mState->quit = true; mState->deinit(); delete mState; From 254a623319126d233d65321c03bce9f6cd094c1a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 03:09:24 -0800 Subject: [PATCH 148/916] Remove a redundant check --- apps/openmw/mwrender/videoplayer.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 81eba2417..817ec0a3f 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -316,9 +316,6 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder } av_free_packet(pkt); - if(is->quit) - return -1; - /* next packet */ if(is->audioq.get(pkt, is) < 0) return -1; From 8cde6db665056dd35aab98ceb036e405c0b34d02 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 03:17:17 -0800 Subject: [PATCH 149/916] We no longer need SDL --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 084363da7..f320c5c3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,9 +163,6 @@ if (USE_MPG123) set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123) endif (USE_MPG123) -find_package (SDL REQUIRED) -set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${SDL_INCLUDE_DIR}) -set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${SDL_LIBRARY}) # Platform specific if (WIN32) From 77852439ce561091596fe749f9b79b33570c3ec7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 16 Dec 2012 12:52:23 +0100 Subject: [PATCH 150/916] moved ColumnBase and Column struct into a separate translation unit --- apps/opencs/model/world/columnbase.cpp | 13 ++++++ apps/opencs/model/world/columnbase.hpp | 57 ++++++++++++++++++++++++ apps/opencs/model/world/idcollection.cpp | 11 ----- apps/opencs/model/world/idcollection.hpp | 45 +------------------ 4 files changed, 71 insertions(+), 55 deletions(-) create mode 100644 apps/opencs/model/world/columnbase.cpp create mode 100644 apps/opencs/model/world/columnbase.hpp diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp new file mode 100644 index 000000000..7adc7e6c3 --- /dev/null +++ b/apps/opencs/model/world/columnbase.cpp @@ -0,0 +1,13 @@ + +#include "columnbase.hpp" + +CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags) +: mTitle (title), mFlags (flags) +{} + +CSMWorld::ColumnBase::~ColumnBase() {} + +bool CSMWorld::ColumnBase::isUserEditable() const +{ + return isEditable(); +} \ No newline at end of file diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp new file mode 100644 index 000000000..dc077eff6 --- /dev/null +++ b/apps/opencs/model/world/columnbase.hpp @@ -0,0 +1,57 @@ +#ifndef CSM_WOLRD_COLUMNBASE_H +#define CSM_WOLRD_COLUMNBASE_H + +#include + +#include +#include + +#include "record.hpp" + +namespace CSMWorld +{ + struct ColumnBase + { + enum Roles + { + Role_Flags = Qt::UserRole + }; + + enum Flags + { + Flag_Table = 1, // column should be displayed in table view + Flag_Dialogue = 2 // column should be displayed in dialogue view + }; + + std::string mTitle; + int mFlags; + + ColumnBase (const std::string& title, int flag); + + virtual ~ColumnBase(); + + virtual bool isEditable() const = 0; + + virtual bool isUserEditable() const; + ///< Can this column be edited directly by the user? + }; + + template + struct Column : public ColumnBase + { + std::string mTitle; + int mFlags; + + Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue) + : ColumnBase (title, flags) {} + + virtual QVariant get (const Record& record) const = 0; + + virtual void set (Record& record, const QVariant& data) + { + throw std::logic_error ("Column " + mTitle + " is not editable"); + } + }; +} + +#endif diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp index c6469ea98..fc4bb1ef6 100644 --- a/apps/opencs/model/world/idcollection.cpp +++ b/apps/opencs/model/world/idcollection.cpp @@ -1,17 +1,6 @@ #include "idcollection.hpp" -CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags) -: mTitle (title), mFlags (flags) -{} - -CSMWorld::ColumnBase::~ColumnBase() {} - -bool CSMWorld::ColumnBase::isUserEditable() const -{ - return isEditable(); -} - CSMWorld::IdCollectionBase::IdCollectionBase() {} CSMWorld::IdCollectionBase::~IdCollectionBase() {} \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 5d6f52aa0..1b2d1e349 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -11,53 +11,10 @@ #include -#include "record.hpp" +#include "columnbase.hpp" namespace CSMWorld { - struct ColumnBase - { - enum Roles - { - Role_Flags = Qt::UserRole - }; - - enum Flags - { - Flag_Table = 1, // column should be displayed in table view - Flag_Dialogue = 2 // column should be displayed in dialogue view - }; - - std::string mTitle; - int mFlags; - - ColumnBase (const std::string& title, int flag); - - virtual ~ColumnBase(); - - virtual bool isEditable() const = 0; - - virtual bool isUserEditable() const; - ///< Can this column be edited directly by the user? - }; - - template - struct Column : public ColumnBase - { - std::string mTitle; - int mFlags; - - Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue) - : ColumnBase (title, flags) {} - - virtual QVariant get (const Record& record) const = 0; - - virtual void set (Record& record, const QVariant& data) - { - throw std::logic_error ("Column " + mTitle + " is not editable"); - } - }; - class IdCollectionBase { // not implemented From 3829bbfeca4aaa0b9889e6bffbe9137c751257ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 04:01:27 -0800 Subject: [PATCH 151/916] Look for all available sound input libs as needed, and warn if not found --- CMakeLists.txt | 56 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f320c5c3c..182cc268a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,8 +36,8 @@ option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF) # Sound source selection -option(USE_FFMPEG "use ffmpeg for sound" OFF) -option(USE_AUDIERE "use audiere for sound" OFF) +option(USE_FFMPEG "use ffmpeg for sound" ON) +option(USE_AUDIERE "use audiere for sound" ON) option(USE_MPG123 "use mpg123 + libsndfile for sound" ON) # OS X deployment @@ -137,31 +137,53 @@ set(OPENMW_LIBS ${OENGINE_ALL}) set(OPENMW_LIBS_HEADER) # Sound setup +set(GOT_SOUND_INPUT 0) set(SOUND_INPUT_INCLUDES "") set(SOUND_INPUT_LIBRARY "") set(SOUND_DEFINE "") if (USE_FFMPEG) set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) - find_package(FFmpeg REQUIRED) - set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS}) - set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES}) - set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG) + find_package(FFmpeg) + if (FFMPEG_FOUND) + set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS}) + set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES}) + set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG) + set(GOT_SOUND_INPUT 1) + endif (FFMPEG_FOUND) endif (USE_FFMPEG) -if (USE_AUDIERE) - find_package(Audiere REQUIRED) - set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR}) - set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY}) - set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE) -endif (USE_AUDIERE) +if (USE_AUDIERE AND NOT GOT_SOUND_INPUT) + find_package(Audiere) + if (AUDIERE_FOUND) + set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR}) + set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY}) + set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE) + set(GOT_SOUND_INPUT 1) + endif (AUDIERE_FOUND) +endif (USE_AUDIERE AND NOT GOT_SOUND_INPUT) -if (USE_MPG123) +if (USE_MPG123 AND NOT GOT_SOUND_INPUT) find_package(MPG123 REQUIRED) find_package(SNDFILE REQUIRED) - set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR}) - set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY}) - set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123) -endif (USE_MPG123) + if (MPG123_FOUND AND SNDFILE_FOUND) + set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR}) + set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY}) + set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123) + set(GOT_SOUND_INPUT 1) + endif (MPG123_FOUND AND SNDFILE_FOUND) +endif (USE_MPG123 AND NOT GOT_SOUND_INPUT) + +if (NOT GOT_SOUND_INPUT) + message(WARNING "--------------------") + message(WARNING "Failed to find any sound input packages") + message(WARNING "--------------------") +endif (NOT GOT_SOUND_INPUT) + +if (NOT FFMPEG_FOUND) + message(WARNING "--------------------") + message(WARNING "FFmpeg not found, video playback will be disabled") + message(WARNING "--------------------") +endif (NOT FFMPEG_FOUND) # Platform specific From 6bc526b74d7c939d6ebc1e471b12b719c388f772 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 05:30:38 -0800 Subject: [PATCH 152/916] Avoid another loop for decoding audio --- apps/openmw/mwrender/videoplayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 817ec0a3f..1c22b7b3d 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -401,7 +401,7 @@ public: while(total < len) { - while(mFramePos >= mFrameSize) + if(mFramePos >= mFrameSize) { /* We have already sent all our data; get more */ mFrameSize = audio_decode_frame(mFrame); @@ -413,6 +413,7 @@ public: mFramePos = std::min(mFrameSize, sample_skip); sample_skip -= mFramePos; + continue; } size_t len1 = len - total; From c92cde2be92f092cbb00249457f39e355146fde3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 05:50:20 -0800 Subject: [PATCH 153/916] Properly flush packet queues when at EOF Note: the previous flush method was renamed to clear. Flushing a queue allows consumers to retrieve queued packets, but not expect any more to come in. --- apps/openmw/mwrender/videoplayer.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 1c22b7b3d..d2e317b71 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -29,12 +29,13 @@ enum { struct PacketQueue { PacketQueue() - : first_pkt(NULL), last_pkt(NULL), nb_packets(0), size(0) + : first_pkt(NULL), last_pkt(NULL), flushing(false), nb_packets(0), size(0) { } ~PacketQueue() - { flush(); } + { clear(); } AVPacketList *first_pkt, *last_pkt; + volatile bool flushing; int nb_packets; int size; @@ -45,6 +46,7 @@ struct PacketQueue { int get(AVPacket *pkt, VideoState *is); void flush(); + void clear(); }; struct VideoPicture { @@ -202,6 +204,8 @@ int PacketQueue::get(AVPacket *pkt, VideoState *is) return 1; } + if(this->flushing) + break; this->cond.wait(lock); } @@ -209,6 +213,12 @@ int PacketQueue::get(AVPacket *pkt, VideoState *is) } void PacketQueue::flush() +{ + this->flushing = true; + this->cond.notify_one(); +} + +void PacketQueue::clear() { AVPacketList *pkt, *pkt1; @@ -753,7 +763,10 @@ void VideoState::decode_thread_loop(VideoState *self) else av_free_packet(packet); } + /* all done - wait for it */ + self->videoq.flush(); + self->audioq.flush(); while(!self->quit) { // EOF reached, all packets processed, we can exit now From c5dd0e19688b388b6e4e978d5ecf07ec14f5085d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Dec 2012 16:05:31 +0100 Subject: [PATCH 154/916] New Game button --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwgui/mainmenu.cpp | 25 ++++++++++++++++++++----- apps/openmw/mwgui/mainmenu.hpp | 8 +++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 15 ++++++++++++++- apps/openmw/mwworld/worldimp.hpp | 3 +++ 6 files changed, 47 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 198a20d45..3c707d196 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -82,6 +82,8 @@ namespace MWBase virtual OEngine::Render::Fader* getFader() = 0; ///< \ŧodo remove this function. Rendering details should not be exposed. + virtual void newGame() = 0; + virtual MWWorld::CellStore *getExterior (int x, int y) = 0; virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index e98b75e9b..b19f3de6d 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -6,12 +6,15 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "confirmationdialog.hpp" + namespace MWGui { - MainMenu::MainMenu(int w, int h) + MainMenu::MainMenu(MWBase::WindowManager& parWindowManager, int w, int h) : OEngine::GUI::Layout("openmw_mainmenu.layout") , mButtonBox(0) + , mDialog(parWindowManager) { onResChange(w,h); } @@ -20,7 +23,7 @@ namespace MWGui { setCoord(0,0,w,h); - int height = 64 * 3; + int height = 64 * 4; if (mButtonBox) MyGUI::Gui::getInstance ().destroyWidget(mButtonBox); @@ -33,12 +36,11 @@ namespace MWGui mReturn->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::returnToGame); curH += 64; - - /* mNewGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); + mNewGame->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::newGame); mNewGame->setImageResource ("Menu_NewGame"); curH += 64; - +/* mLoadGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); mLoadGame->setImageResource ("Menu_LoadGame"); curH += 64; @@ -81,4 +83,17 @@ namespace MWGui Ogre::Root::getSingleton ().queueEndRendering (); } + void MainMenu::newGame(MyGUI::Widget* sender) + { + mDialog.open ("#{sNotifyMessage54}"); + mDialog.eventOkClicked.clear(); + mDialog.eventCancelClicked.clear(); + mDialog.eventOkClicked += MyGUI::newDelegate(this, &MainMenu::newGameConfirmed); + } + + void MainMenu::newGameConfirmed() + { + MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); + MWBase::Environment::get().getWorld ()->newGame(); + } } diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index fd583d187..ab48f29d9 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -1,12 +1,14 @@ #include +#include "confirmationdialog.hpp" + namespace MWGui { class MainMenu : public OEngine::GUI::Layout { public: - MainMenu(int w, int h); + MainMenu(MWBase::WindowManager& parWindowManager, int w, int h); void onResChange(int w, int h); @@ -24,6 +26,10 @@ namespace MWGui void returnToGame(MyGUI::Widget* sender); void showOptions(MyGUI::Widget* sender); void exitGame(MyGUI::Widget* sender); + void newGame(MyGUI::Widget* sender); + void newGameConfirmed(); + + ConfirmationDialog mDialog; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 373546aa8..627f8f339 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -139,7 +139,7 @@ WindowManager::WindowManager( mDragAndDrop->mDraggedWidget = 0; mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - mMenu = new MainMenu(w,h); + mMenu = new MainMenu(*this, w,h); mMap = new MapWindow(*this, cacheDir); mStatsWindow = new StatsWindow(*this); mConsole = new Console(w,h, consoleOnlyScripts); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8eb121d37..f1fb67632 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -170,7 +170,7 @@ namespace MWWorld const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), - mSky (true), mCells (mStore, mEsm), + mSky (true), mCells (mStore, mEsm), mNewGameStarted(false), mNumFacing(0) { mPhysics = new PhysicsSystem(renderer); @@ -1015,6 +1015,12 @@ namespace MWWorld } } } + + if (mNewGameStarted) + { + playVideo ("mw_intro.bik"); + mNewGameStarted = false; + } } bool World::isCellExterior() const @@ -1296,4 +1302,11 @@ namespace MWWorld { mRendering->stopVideo(); } + + void World::newGame () + { + // set new game mark + mGlobalVariables->setInt ("chargenstate", 1); + mNewGameStarted = true; // in order to play the intro video at the end of the next frame + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1c1352913..a58e70d12 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -60,6 +60,7 @@ namespace MWWorld MWWorld::Globals *mGlobalVariables; MWWorld::PhysicsSystem *mPhysics; bool mSky; + bool mNewGameStarted; Cells mCells; @@ -102,6 +103,8 @@ namespace MWWorld virtual OEngine::Render::Fader* getFader(); ///< \ŧodo remove this function. Rendering details should not be exposed. + virtual void newGame(); + virtual CellStore *getExterior (int x, int y); virtual CellStore *getInterior (const std::string& name); From 86671096ec89960405726594a50e5a7fa787b075 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Dec 2012 16:14:49 +0100 Subject: [PATCH 155/916] remove commandline switch for new game --- apps/openmw/engine.cpp | 10 ++-------- apps/openmw/engine.hpp | 4 ---- apps/openmw/main.cpp | 4 ---- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/mainmenu.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++++++++--- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 8 +------- apps/openmw/mwworld/worldimp.hpp | 2 +- 9 files changed, 19 insertions(+), 28 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2299053cd..08e24b5d6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -125,7 +125,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mFpsLevel(0) , mDebug (false) , mVerboseScripts (false) - , mNewGame (false) , mUseSound (true) , mCompileAll (false) , mScriptContext (0) @@ -237,11 +236,6 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) mVerboseScripts = scriptsVerbosity; } -void OMW::Engine::setNewGame(bool newGame) -{ - mNewGame = newGame; -} - // Initialise and enter main loop. void OMW::Engine::go() @@ -332,13 +326,13 @@ void OMW::Engine::go() // Create the world mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); + mResDir, mCfgMgr.getCachePath(), mEncoding, mFallbackMap)); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); mEnvironment.setWindowManager (new MWGui::WindowManager( - mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode)); // Create sound system diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 57402c91e..b13ec4368 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -68,7 +68,6 @@ namespace OMW int mFpsLevel; bool mDebug; bool mVerboseScripts; - bool mNewGame; bool mUseSound; bool mCompileAll; std::string mFocusName; @@ -138,9 +137,6 @@ namespace OMW /// Disable or enable all sounds void setSoundUsage(bool soundUsage); - /// Start as a new game. - void setNewGame(bool newGame); - /// Initialise and enter main loop. void go(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 0563fdbbb..6b31f3ade 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -133,9 +133,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-run", bpo::value()->default_value(""), "select a file containing a list of console commands that is executed on startup") - ("new-game", bpo::value()->implicit_value(true) - ->default_value(false), "activate char gen/new game mechanics") - ("fs-strict", bpo::value()->implicit_value(true) ->default_value(false), "strict file system handling (no case folding)") @@ -238,7 +235,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // startup-settings engine.setCell(variables["start"].as()); - engine.setNewGame(variables["new-game"].as()); // other settings engine.setDebugMode(variables["debug"].as()); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c177912d4..9df75870d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -79,6 +79,8 @@ namespace MWBase */ virtual void update() = 0; + virtual void newGame() = 0; + virtual void pushGuiMode (MWGui::GuiMode mode) = 0; virtual void popGuiMode() = 0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index b19f3de6d..0f74f6e14 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -94,6 +94,7 @@ namespace MWGui void MainMenu::newGameConfirmed() { MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); + MWBase::Environment::get().getWindowManager ()->newGame (); MWBase::Environment::get().getWorld ()->newGame(); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 627f8f339..1f5966f72 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -54,7 +54,7 @@ using namespace MWGui; WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, + const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts) : mGuiManager(NULL) , mHud(NULL) @@ -95,8 +95,8 @@ WindowManager::WindowManager( , mGui(NULL) , mGarbageDialogs() , mShown(GW_ALL) - , mAllowed(newGame ? GW_None : GW_ALL) - , mRestAllowed(newGame ? false : true) + , mAllowed(GW_ALL) + , mRestAllowed(true) , mShowFPSLevel(fpsLevel) , mFPS(0.0f) , mTriangleCount(0) @@ -1041,3 +1041,9 @@ void WindowManager::startTraining(MWWorld::Ptr actor) { mTrainingWindow->startTraining(actor); } + +void WindowManager::newGame () +{ + mAllowed = GW_None; + mRestAllowed = false; +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 2e684b5da..db5c22348 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -74,7 +74,7 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, + WindowManager(const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts); virtual ~WindowManager(); @@ -86,6 +86,8 @@ namespace MWGui */ virtual void update(); + virtual void newGame(); + virtual void pushGuiMode(GuiMode mode); virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f1fb67632..afcdb8d39 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -167,7 +167,7 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, + const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), mNewGameStarted(false), @@ -197,12 +197,6 @@ namespace MWWorld // global variables mGlobalVariables = new Globals (mStore); - if (newGame) - { - // set new game mark - mGlobalVariables->setInt ("chargenstate", 1); - } - mGlobalVariables->setInt ("pcrace", 3); mWorldScene = new Scene(*mRendering, mPhysics); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a58e70d12..8f89ecff3 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -95,7 +95,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, + const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, const std::string& encoding, std::map fallbackMap); virtual ~World(); From f0f521a4e0550ae454100065fc2a0a1b05fed5ac Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Dec 2012 16:55:59 +0100 Subject: [PATCH 156/916] enableRestMenu -> enableRest --- apps/openmw/mwscript/guiextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 72c2db164..7d437f3c0 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -181,7 +181,7 @@ opcodeEnableStatsReviewMenu); extensions.registerInstruction ("enablemapmenu", "", opcodeEnableMapMenu); extensions.registerInstruction ("enablestatsmenu", "", opcodeEnableStatsMenu); - extensions.registerInstruction ("enablerestmenu", "", opcodeEnableRest); + extensions.registerInstruction ("enablerest", "", opcodeEnableRest); extensions.registerInstruction ("enablelevelupmenu", "", opcodeEnableRest); extensions.registerInstruction ("showrestmenu", "", opcodeShowRestMenu); From 06fd66e99dfd6c8aea5b29c8e881baa852e2315a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 16 Dec 2012 11:49:46 -0800 Subject: [PATCH 157/916] Move some fields to the class they're used in --- apps/openmw/mwrender/videoplayer.cpp | 47 ++++++++++++++-------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index d2e317b71..3e1701095 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -61,8 +61,7 @@ struct VideoState { VideoState() : format_ctx(NULL), av_sync_type(AV_SYNC_DEFAULT) , external_clock_base(0.0) - , audio_st(NULL), audio_diff_cum(0.0), audio_diff_avg_coef(0.0), - audio_diff_threshold(0.0), audio_diff_avg_count(0) + , audio_st(NULL) , video_st(NULL), frame_last_pts(0.0), frame_last_delay(0.0), video_clock(0.0), sws_context(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0) @@ -121,10 +120,6 @@ struct VideoState { AVStream** audio_st; PacketQueue audioq; - double audio_diff_cum; /* used for AV difference average computation */ - double audio_diff_avg_coef; - double audio_diff_threshold; - int audio_diff_avg_count; MWBase::SoundPtr AudioTrack; AVStream** video_st; @@ -261,7 +256,13 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder ssize_t mFramePos; ssize_t mFrameSize; - double audio_clock; + double mAudioClock; + + /* averaging filter for audio sync */ + double mAudioDiffAccum; + double mAudioDiffAvgCoef; + double mAudioDiffThreshold; + int mAudioDiffAvgCount; /* Add or subtract samples to get a better sync, return number of bytes to * skip (negative means to duplicate). */ @@ -274,14 +275,13 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder // accumulate the clock difference double diff = is->get_master_clock() - is->get_audio_clock(); - is->audio_diff_cum = diff + is->audio_diff_avg_coef * - is->audio_diff_cum; - if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) - is->audio_diff_avg_count++; + mAudioDiffAccum = diff + mAudioDiffAvgCoef * mAudioDiffAccum; + if(mAudioDiffAvgCount < AUDIO_DIFF_AVG_NB) + mAudioDiffAvgCount++; else { - double avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef); - if(fabs(avg_diff) >= is->audio_diff_threshold) + double avg_diff = mAudioDiffAccum * (1.0 - mAudioDiffAvgCoef); + if(fabs(avg_diff) >= mAudioDiffThreshold) { int n = av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt) * (*is->audio_st)->codec->channels; @@ -317,8 +317,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder if(!got_frame || frame->nb_samples <= 0) continue; - this->audio_clock += (double)frame->nb_samples / - (double)(*is->audio_st)->codec->sample_rate; + mAudioClock += (double)frame->nb_samples / + (double)(*is->audio_st)->codec->sample_rate; /* We have data, return it and come back for more later */ return frame->nb_samples * av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt) * @@ -332,7 +332,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder /* if update, update the audio clock w/pts */ if((uint64_t)pkt->pts != AV_NOPTS_VALUE) - this->audio_clock = av_q2d((*is->audio_st)->time_base)*pkt->pts; + mAudioClock = av_q2d((*is->audio_st)->time_base)*pkt->pts; } } @@ -352,7 +352,12 @@ public: , mFrame(avcodec_alloc_frame()) , mFramePos(0) , mFrameSize(0) - , audio_clock(0.0) + , mAudioClock(0.0) + , mAudioDiffAccum(0.0) + , mAudioDiffAvgCoef(exp(log(0.01 / AUDIO_DIFF_AVG_NB))) + /* Correct audio only if larger error than this */ + , mAudioDiffThreshold(2.0 * 0.050/* 50 ms */) + , mAudioDiffAvgCount(0) { } virtual ~MovieAudioDecoder() { @@ -479,7 +484,7 @@ public: { ssize_t clock_delay = (mFrameSize-mFramePos) / (*is->audio_st)->codec->channels / av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt); - return (size_t)(this->audio_clock*(*is->audio_st)->codec->sample_rate) - clock_delay; + return (size_t)(mAudioClock*(*is->audio_st)->codec->sample_rate) - clock_delay; } }; @@ -809,12 +814,6 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) case AVMEDIA_TYPE_AUDIO: this->audio_st = pFormatCtx->streams + stream_index; - /* averaging filter for audio sync */ - this->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); - this->audio_diff_avg_count = 0; - /* Correct audio only if larger error than this */ - this->audio_diff_threshold = 2.0 * 0.050/* 50 ms */; - decoder.reset(new MovieAudioDecoder(this)); this->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); if(!this->AudioTrack) From 26660110e5f900c5ca93993b212fec66c390b0bd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2012 00:20:56 -0800 Subject: [PATCH 158/916] Allow building the video player without ffmpeg (playVideo will always throw an exception) --- apps/openmw/mwrender/videoplayer.cpp | 122 ++++++++++++++++++--------- apps/openmw/mwrender/videoplayer.hpp | 22 ++--- 2 files changed, 89 insertions(+), 55 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 3e1701095..9c4546d15 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1,5 +1,15 @@ #include "videoplayer.hpp" +#define __STDC_CONSTANT_MACROS +#include + +#include +#include + +#include +#include + +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" @@ -8,17 +18,24 @@ #include "../mwsound/sound.hpp" +namespace MWRender +{ + +#ifdef OPENMW_USE_FFMPEG + +extern "C" +{ +#include +#include +#include +} + #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) #define MAX_VIDEOQ_SIZE (5 * 256 * 1024) #define AV_SYNC_THRESHOLD 0.01 -#define SAMPLE_CORRECTION_PERCENT_MAX 10 #define AUDIO_DIFF_AVG_NB 20 #define VIDEO_PICTURE_QUEUE_SIZE 1 - -namespace MWRender -{ - enum { AV_SYNC_AUDIO_MASTER, AV_SYNC_VIDEO_MASTER, @@ -27,6 +44,7 @@ enum { AV_SYNC_DEFAULT = AV_SYNC_EXTERNAL_MASTER }; + struct PacketQueue { PacketQueue() : first_pkt(NULL), last_pkt(NULL), flushing(false), nb_packets(0), size(0) @@ -66,16 +84,21 @@ struct VideoState { video_clock(0.0), sws_context(NULL), rgbaFrame(NULL), pictq_size(0), pictq_rindex(0), pictq_windex(0) , refresh_rate_ms(10), refresh(false), quit(false), display_ready(false) - { } + { + // Register all formats and codecs + av_register_all(); + } ~VideoState() - { } + { deinit(); } void init(const std::string& resourceName); void deinit(); int stream_open(int stream_index, AVFormatContext *pFormatCtx); + bool update(Ogre::MaterialPtr &mat, Ogre::Rectangle2D *rect, int screen_width, int screen_height); + static void video_thread_loop(VideoState *is); static void decode_thread_loop(VideoState *is); @@ -791,6 +814,35 @@ void VideoState::decode_thread_loop(VideoState *self) } +bool VideoState::update(Ogre::MaterialPtr &mat, Ogre::Rectangle2D *rect, int screen_width, int screen_height) +{ + if(this->quit) + return false; + + if(this->refresh) + { + this->refresh = false; + this->video_refresh_timer(); + // Would be nice not to do this all the time... + if(this->display_ready) + mat->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("VideoTexture"); + + // Correct aspect ratio by adding black bars + double videoaspect = av_q2d((*this->video_st)->codec->sample_aspect_ratio); + if(videoaspect == 0.0) + videoaspect = 1.0; + videoaspect *= static_cast((*this->video_st)->codec->width) / (*this->video_st)->codec->height; + + double screenaspect = static_cast(screen_width) / screen_height; + double aspect_correction = videoaspect / screenaspect; + + rect->setCorners(std::max(-1.0, -1.0 * aspect_correction), std::min( 1.0, 1.0 / aspect_correction), + std::min( 1.0, 1.0 * aspect_correction), std::max(-1.0, -1.0 / aspect_correction)); + } + return true; +} + + int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) { MWSound::DecoderPtr decoder; @@ -899,12 +951,7 @@ void VideoState::init(const std::string& resourceName) this->parse_thread = boost::thread(decode_thread_loop, this); } - catch(std::runtime_error& e) - { - this->quit = true; - throw; - } - catch(Ogre::Exception& e) + catch(...) { this->quit = true; throw; @@ -913,6 +960,8 @@ void VideoState::init(const std::string& resourceName) void VideoState::deinit() { + this->quit = true; + this->audioq.cond.notify_one(); this->videoq.cond.notify_one(); @@ -939,6 +988,27 @@ void VideoState::deinit() } } +#else // defined OPENMW_USE_FFMPEG + +class VideoState +{ +public: + VideoState() { } + + void init(const std::string& resourceName) + { + throw std::runtime_error("FFmpeg not supported, cannot play video \""+resourceName+"\""); + } + void deinit() { } + + void close() { } + + bool update(Ogre::MaterialPtr &mat, Ogre::Rectangle2D *rect, int screen_width, int screen_height) + { return false; } +}; + +#endif // defined OPENMW_USE_FFMPEG + VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) : mState(NULL) @@ -1009,9 +1079,6 @@ VideoPlayer::~VideoPlayer() void VideoPlayer::playVideo(const std::string &resourceName) { - // Register all formats and codecs - av_register_all(); - if(mState) close(); @@ -1041,34 +1108,13 @@ void VideoPlayer::update () { if(mState) { - if(mState->quit) + if(!mState->update(mVideoMaterial, mRectangle, mWidth, mHeight)) close(); - else if(mState->refresh) - { - mState->refresh = false; - mState->video_refresh_timer(); - // Would be nice not to do this all the time... - if(mState->display_ready) - mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("VideoTexture"); - - // Correct aspect ratio by adding black bars - double videoaspect = av_q2d((*mState->video_st)->codec->sample_aspect_ratio); - if(videoaspect == 0.0) - videoaspect = 1.0; - videoaspect *= static_cast((*mState->video_st)->codec->width) / (*mState->video_st)->codec->height; - - double screenaspect = static_cast(mWidth) / mHeight; - double aspect_correction = videoaspect / screenaspect; - - mRectangle->setCorners(std::max(-1.0, -1.0 * aspect_correction), std::min( 1.0, 1.0 / aspect_correction), - std::min( 1.0, 1.0 * aspect_correction), std::max(-1.0, -1.0 / aspect_correction)); - } } } void VideoPlayer::close() { - mState->quit = true; mState->deinit(); delete mState; diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index c82a16e15..d8c1902aa 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -1,27 +1,15 @@ #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H -#include -#include +#include -#include - - -#define __STDC_CONSTANT_MACROS -#include -extern "C" +namespace Ogre { -#include -#include -#include + class SceneManager; + class SceneNode; + class Rectangle2D; } -#include -#include - -#include "../mwbase/soundmanager.hpp" - - namespace MWRender { struct VideoState; From 9e842a0bbb96b5a282307342d89b8a29a9718dc3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2012 00:41:04 -0800 Subject: [PATCH 159/916] Fix for trying to play videos when not supported --- apps/openmw/mwrender/videoplayer.cpp | 125 ++++++++++++++------------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 9c4546d15..9fdd051b6 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -896,66 +896,58 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) void VideoState::init(const std::string& resourceName) { - try + int video_index = -1; + int audio_index = -1; + unsigned int i; + + this->av_sync_type = AV_SYNC_DEFAULT; + this->refresh_rate_ms = 10; + this->refresh = false; + this->quit = false; + + this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); + if(this->stream.isNull()) + throw std::runtime_error("Failed to open video resource"); + + AVIOContext *ioCtx = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); + if(!ioCtx) throw std::runtime_error("Failed to allocate AVIOContext"); + + this->format_ctx = avformat_alloc_context(); + if(this->format_ctx) + this->format_ctx->pb = ioCtx; + + // Open video file + /// \todo leak here, ffmpeg or valgrind bug ? + if(!this->format_ctx || avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) { - int video_index = -1; - int audio_index = -1; - unsigned int i; - - this->av_sync_type = AV_SYNC_DEFAULT; - this->refresh_rate_ms = 10; - this->refresh = false; - this->quit = false; - - this->stream = Ogre::ResourceGroupManager::getSingleton().openResource(resourceName); - if(this->stream.isNull()) - throw std::runtime_error("Failed to open video resource"); - - AVIOContext *ioCtx = avio_alloc_context(NULL, 0, 0, this, OgreResource_Read, OgreResource_Write, OgreResource_Seek); - if(!ioCtx) throw std::runtime_error("Failed to allocate AVIOContext"); - - this->format_ctx = avformat_alloc_context(); - if(this->format_ctx) - this->format_ctx->pb = ioCtx; - - // Open video file - /// \todo leak here, ffmpeg or valgrind bug ? - if(!this->format_ctx || avformat_open_input(&this->format_ctx, resourceName.c_str(), NULL, NULL)) - { - // "Note that a user-supplied AVFormatContext will be freed on failure." - this->format_ctx = NULL; - av_free(ioCtx); - throw std::runtime_error("Failed to open video input"); - } - - // Retrieve stream information - if(avformat_find_stream_info(this->format_ctx, NULL) < 0) - throw std::runtime_error("Failed to retrieve stream information"); - - // Dump information about file onto standard error - av_dump_format(this->format_ctx, 0, resourceName.c_str(), 0); - - for(i = 0;i < this->format_ctx->nb_streams;i++) - { - if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) - video_index = i; - if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) - audio_index = i; - } - - this->external_clock_base = av_gettime(); - if(audio_index >= 0) - this->stream_open(audio_index, this->format_ctx); - if(video_index >= 0) - this->stream_open(video_index, this->format_ctx); - - this->parse_thread = boost::thread(decode_thread_loop, this); + // "Note that a user-supplied AVFormatContext will be freed on failure." + this->format_ctx = NULL; + av_free(ioCtx); + throw std::runtime_error("Failed to open video input"); } - catch(...) + + // Retrieve stream information + if(avformat_find_stream_info(this->format_ctx, NULL) < 0) + throw std::runtime_error("Failed to retrieve stream information"); + + // Dump information about file onto standard error + av_dump_format(this->format_ctx, 0, resourceName.c_str(), 0); + + for(i = 0;i < this->format_ctx->nb_streams;i++) { - this->quit = true; - throw; + if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) + video_index = i; + if(this->format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) + audio_index = i; } + + this->external_clock_base = av_gettime(); + if(audio_index >= 0) + this->stream_open(audio_index, this->format_ctx); + if(video_index >= 0) + this->stream_open(video_index, this->format_ctx); + + this->parse_thread = boost::thread(decode_thread_loop, this); } void VideoState::deinit() @@ -997,7 +989,7 @@ public: void init(const std::string& resourceName) { - throw std::runtime_error("FFmpeg not supported, cannot play video \""+resourceName+"\""); + throw std::runtime_error("FFmpeg not supported, cannot play \""+resourceName+"\""); } void deinit() { } @@ -1100,8 +1092,14 @@ void VideoPlayer::playVideo(const std::string &resourceName) MWBase::Environment::get().getSoundManager()->pauseAllSounds(); - mState = new VideoState; - mState->init(resourceName); + try { + mState = new VideoState; + mState->init(resourceName); + } + catch(std::exception& e) { + std::cerr<< "Failed to play video: "<deinit(); + if(mState) + { + mState->deinit(); - delete mState; - mState = NULL; + delete mState; + mState = NULL; + } MWBase::Environment::get().getSoundManager()->resumeAllSounds(); From 58ab3407b7ccbe5b395db4ed66e2587a68c091f4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2012 04:17:06 -0800 Subject: [PATCH 160/916] Constify a couple fields --- apps/openmw/mwrender/videoplayer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 9fdd051b6..38f7a9d16 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -283,9 +283,9 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder /* averaging filter for audio sync */ double mAudioDiffAccum; - double mAudioDiffAvgCoef; - double mAudioDiffThreshold; - int mAudioDiffAvgCount; + const double mAudioDiffAvgCoef; + const double mAudioDiffThreshold; + int mAudioDiffAvgCount; /* Add or subtract samples to get a better sync, return number of bytes to * skip (negative means to duplicate). */ From 4373218746eea967d4275c9363ae65f80b4202b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2012 06:56:30 -0800 Subject: [PATCH 161/916] Fix audio stream check --- apps/openmw/mwrender/videoplayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 38f7a9d16..56312aa26 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -767,7 +767,7 @@ void VideoState::decode_thread_loop(VideoState *self) try { - if(!self->video_st && !self->audio_st < 0) + if(!self->video_st && !self->audio_st) throw std::runtime_error("No streams to decode"); // main decode loop From 67485d3454ea3dca7812b951ed76f3b96c2b807e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2012 07:15:53 -0800 Subject: [PATCH 162/916] Store the AVStream in the decoder for easy referencing --- apps/openmw/mwrender/videoplayer.cpp | 72 ++++++++++++++-------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 56312aa26..9c72e9919 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -272,7 +272,8 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder { av_free_packet(this); } }; - VideoState *is; + VideoState *mVideoState; + AVStream *mAVStream; AutoAVPacket mPacket; AVFrame *mFrame; @@ -291,13 +292,13 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder * skip (negative means to duplicate). */ int synchronize_audio() { - if(is->av_sync_type == AV_SYNC_AUDIO_MASTER) + if(mVideoState->av_sync_type == AV_SYNC_AUDIO_MASTER) return 0; int sample_skip = 0; // accumulate the clock difference - double diff = is->get_master_clock() - is->get_audio_clock(); + double diff = mVideoState->get_master_clock() - mVideoState->get_audio_clock(); mAudioDiffAccum = diff + mAudioDiffAvgCoef * mAudioDiffAccum; if(mAudioDiffAvgCount < AUDIO_DIFF_AVG_NB) mAudioDiffAvgCount++; @@ -306,9 +307,9 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder double avg_diff = mAudioDiffAccum * (1.0 - mAudioDiffAvgCoef); if(fabs(avg_diff) >= mAudioDiffThreshold) { - int n = av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt) * - (*is->audio_st)->codec->channels; - sample_skip = ((int)(diff * (*is->audio_st)->codec->sample_rate) * n); + int n = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) * + mAVStream->codec->channels; + sample_skip = ((int)(diff * mAVStream->codec->sample_rate) * n); } } @@ -325,7 +326,7 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder { int len1, got_frame; - len1 = avcodec_decode_audio4((*is->audio_st)->codec, frame, &got_frame, pkt); + len1 = avcodec_decode_audio4(mAVStream->codec, frame, &got_frame, pkt); if(len1 < 0) break; if(len1 <= pkt->size) @@ -341,21 +342,21 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder continue; mAudioClock += (double)frame->nb_samples / - (double)(*is->audio_st)->codec->sample_rate; + (double)mAVStream->codec->sample_rate; /* We have data, return it and come back for more later */ - return frame->nb_samples * av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt) * - (*is->audio_st)->codec->channels; + return frame->nb_samples * mAVStream->codec->channels * + av_get_bytes_per_sample(mAVStream->codec->sample_fmt); } av_free_packet(pkt); /* next packet */ - if(is->audioq.get(pkt, is) < 0) + if(mVideoState->audioq.get(pkt, mVideoState) < 0) return -1; /* if update, update the audio clock w/pts */ if((uint64_t)pkt->pts != AV_NOPTS_VALUE) - mAudioClock = av_q2d((*is->audio_st)->time_base)*pkt->pts; + mAudioClock = av_q2d(mAVStream->time_base)*pkt->pts; } } @@ -365,13 +366,14 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder void close() { } std::string getName() - { return is->stream->getName(); } + { return mVideoState->stream->getName(); } void rewind() { } public: - MovieAudioDecoder(VideoState *_is) - : is(_is) + MovieAudioDecoder(VideoState *is) + : mVideoState(is) + , mAVStream(*is->audio_st) , mFrame(avcodec_alloc_frame()) , mFramePos(0) , mFrameSize(0) @@ -389,47 +391,47 @@ public: void getInfo(int *samplerate, MWSound::ChannelConfig *chans, MWSound::SampleType * type) { - if((*is->audio_st)->codec->sample_fmt == AV_SAMPLE_FMT_U8) + if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_U8) *type = MWSound::SampleType_UInt8; - else if((*is->audio_st)->codec->sample_fmt == AV_SAMPLE_FMT_S16) + else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = MWSound::SampleType_Int16; else fail(std::string("Unsupported sample format: ")+ - av_get_sample_fmt_name((*is->audio_st)->codec->sample_fmt)); + av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); - if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_MONO) + if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_MONO) *chans = MWSound::ChannelConfig_Mono; - else if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_STEREO) + else if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_STEREO) *chans = MWSound::ChannelConfig_Stereo; - else if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_QUAD) + else if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_QUAD) *chans = MWSound::ChannelConfig_Quad; - else if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_5POINT1) + else if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_5POINT1) *chans = MWSound::ChannelConfig_5point1; - else if((*is->audio_st)->codec->channel_layout == AV_CH_LAYOUT_7POINT1) + else if(mAVStream->codec->channel_layout == AV_CH_LAYOUT_7POINT1) *chans = MWSound::ChannelConfig_7point1; - else if((*is->audio_st)->codec->channel_layout == 0) + else if(mAVStream->codec->channel_layout == 0) { /* Unknown channel layout. Try to guess. */ - if((*is->audio_st)->codec->channels == 1) + if(mAVStream->codec->channels == 1) *chans = MWSound::ChannelConfig_Mono; - else if((*is->audio_st)->codec->channels == 2) + else if(mAVStream->codec->channels == 2) *chans = MWSound::ChannelConfig_Stereo; else { std::stringstream sstr("Unsupported raw channel count: "); - sstr << (*is->audio_st)->codec->channels; + sstr << mAVStream->codec->channels; fail(sstr.str()); } } else { char str[1024]; - av_get_channel_layout_string(str, sizeof(str), (*is->audio_st)->codec->channels, - (*is->audio_st)->codec->channel_layout); + av_get_channel_layout_string(str, sizeof(str), mAVStream->codec->channels, + mAVStream->codec->channel_layout); fail(std::string("Unsupported channel layout: ")+str); } - *samplerate = (*is->audio_st)->codec->sample_rate; + *samplerate = mAVStream->codec->sample_rate; } size_t read(char *stream, size_t len) @@ -464,8 +466,8 @@ public: { len1 = std::min(len1, -mFramePos); - int n = av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt) * - (*is->audio_st)->codec->channels; + int n = av_get_bytes_per_sample(mAVStream->codec->sample_fmt) * + mAVStream->codec->channels; /* add samples by copying the first sample*/ if(n == 1) @@ -505,9 +507,9 @@ public: size_t getSampleOffset() { - ssize_t clock_delay = (mFrameSize-mFramePos) / (*is->audio_st)->codec->channels / - av_get_bytes_per_sample((*is->audio_st)->codec->sample_fmt); - return (size_t)(mAudioClock*(*is->audio_st)->codec->sample_rate) - clock_delay; + ssize_t clock_delay = (mFrameSize-mFramePos) / mAVStream->codec->channels / + av_get_bytes_per_sample(mAVStream->codec->sample_fmt); + return (size_t)(mAudioClock*mAVStream->codec->sample_rate) - clock_delay; } }; From 32f051d61dfe6be90bfacc4413d560c63a31ed64 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Mon, 17 Dec 2012 23:13:33 +0100 Subject: [PATCH 163/916] Remove 'GMST fixing' for dirty GMST records The 'fixing' for so-called dirty GMSTs does not work properly in its current state anyway, so it should be removed. Fixing the 'GMST fixing' might not be possible, because whether or not a GMST is 'dirty' depends on the language version of MW. Therefore different 'fixing' algorithms would be required for the different MW localisations, and I do not see a good reason why GMST values should be hard-coded in the GMST load procedure. In my opinion, it only clutters the code. Last but not least, I believe that it is not the task of the engine to clean ESM files from dirty entries. That is a job for the modders, who should only release clean ESM/ESP files in the first place. The engine should not need to worry about whether a file is 'dirty' or not. That is why I believe a feature for cleaning ESM/ESP files shall not be part of the engine. --- components/esm/loadgmst.cpp | 139 +----------------------------------- components/esm/loadgmst.hpp | 60 ---------------- 2 files changed, 1 insertion(+), 198 deletions(-) diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index 14e29f4ae..6ce20f935 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -10,138 +10,10 @@ namespace ESM { -/// \todo Review GMST "fixing". Probably remove completely or at least make it optional. Its definitely not -/// working properly in its current state and I doubt it can be fixed without breaking other stuff. - -// Some handy macros -#define cI(s,x) { label = (s); boost::algorithm::to_lower(label); if (mId == label) return (mI == (x)); } -#define cF(s,x) { label = (s); boost::algorithm::to_lower(label); if (mId == label) return (mF == (x)); } -#define cS(s,x) { label = (s); boost::algorithm::to_lower(label); if (mId == label) return (mStr == (x)); } - -bool GameSetting::isDirtyTribunal() -{ - /* - Here, mId contains the game setting name, and we check the - setting for certain values. If it matches, this is a "mDirty" - entry. The correct entry (as defined in Tribunal and Bloodmoon - esms) are given in the comments. Many of the values are correct, - and are marked as 'same'. We still ignore them though, as they - are still in the wrong file and might override custom values - from other mods. - */ - - std::string label; - // Strings - cS("sProfitValue", "Profit Value"); // 'Profit:' - cS("sEditNote", "Edit Note"); // same - cS("sDeleteNote", "Delete Note?"); // same - cS("sMaxSale", "Max Sale"); // 'Seller Max' - cS("sMagicFabricantID", "Fabricant"); // 'Fabricant_summon' - cS("sTeleportDisabled", - "Teleportation magic does not work here.");// same - cS("sLevitateDisabled", - "Levitation magic does not work here."); // same - cS("sCompanionShare", "Companion Share"); // 'Share' - cS("sCompanionWarningButtonOne", - "Let the mercenary quit."); // same - cS("sCompanionWarningButtonTwo", - "Return to Companion Share display."); // same - cS("sCompanionWarningMessage", - "Your mercenary is poorer now than when he contracted with you. Your mercenary will quit if you do not give him gold or goods to bring his Profit Value to a positive value."); - // 'Your mercenary is poorer now than when he contracted with - // you. Your mercenary will quit if you do not give him gold - // or goods to bring his Profit to a positive value.' - // [The difference here is "Profit Value" -> "Profit"] - - // Strings that matches the mId - cS("sEffectSummonFabricant", "sEffectSummonFabricant");// 'Summon Fabricant' - return false; -} - -// Bloodmoon variant -bool GameSetting::isDirtyBloodmoon() -{ - std::string label; - // Strings - cS("sWerewolfPopup", "Werewolf"); // same - cS("sWerewolfRestMessage", - "You cannot rest in werewolf form."); // same - cS("sWerewolfRefusal", - "You cannot do this as a werewolf."); // same - cS("sWerewolfAlarmMessage", - "You have been detected changing from a werewolf state."); - // 'You have been detected as a known werewolf.' - - // Strings that matches the mId - cS("sMagicCreature01ID", "sMagicCreature01ID"); // 'BM_wolf_grey_summon' - cS("sMagicCreature02ID", "sMagicCreature02ID"); // 'BM_bear_black_summon' - cS("sMagicCreature03ID", "sMagicCreature03ID"); // 'BM_wolf_bone_summon' - cS("sMagicCreature04ID", "sMagicCreature04ID"); // same - cS("sMagicCreature05ID", "sMagicCreature05ID"); // same - cS("sEffectSummonCreature01", "sEffectSummonCreature01"); // 'Calf Wolf' - cS("sEffectSummonCreature02", "sEffectSummonCreature02"); // 'Calf Bear' - cS("sEffectSummonCreature03", "sEffectSummonCreature03"); // 'Summon Bonewolf' - cS("sEffectSummonCreature04", "sEffectSummonCreature04"); // same - cS("sEffectSummonCreature05", "sEffectSummonCreature05"); // same - - // Integers - cI("iWereWolfBounty", 10000); // 1000 - cI("iWereWolfFightMod", 100); // same - cI("iWereWolfFleeMod", 100); // same - cI("iWereWolfLevelToAttack", 20); // same - - // Floats - cF("fFleeDistance", 3000); // same - cF("fCombatDistanceWerewolfMod", 0.3); // same - cF("fWereWolfFatigue", 400); // same - cF("fWereWolfEnchant", 1); // 0 - cF("fWereWolfArmorer", 1); // 0 - cF("fWereWolfBlock", 1); // 0 - cF("fWereWolfSneak", 1); // 95 - cF("fWereWolfDestruction", 1); // 0 - cF("fWereWolfEndurance", 150); // same - cF("fWereWolfConjuration", 1); // 0 - cF("fWereWolfRestoration", 1); // 0 - cF("fWereWolfAthletics", 150); // 50 - cF("fWereWolfLuck", 1); // 25 - cF("fWereWolfSilverWeaponDamageMult", 1.5); // 2 - cF("fWereWolfMediumArmor", 1); // 0 - cF("fWereWolfShortBlade", 1); // 0 - cF("fWereWolfAcrobatics", 150); // 80 - cF("fWereWolfSpeechcraft", 1); // 0 - cF("fWereWolfAlteration", 1); // 0 - cF("fWereWolfIllusion", 1); // 0 - cF("fWereWolfLongBlade", 1); // 0 - cF("fWereWolfMarksman", 1); // 0 - cF("fWereWolfHandtoHand", 100); // same - cF("fWereWolfIntellegence", 1); // 0 - cF("fWereWolfAlchemy", 1); // 0 - cF("fWereWolfUnarmored", 100); // same - cF("fWereWolfAxe", 1); // 0 - cF("fWereWolfRunMult", 1.5); // 1.3 - cF("fWereWolfMagicka", 100); // same - cF("fWereWolfAgility", 150); // same - cF("fWereWolfBluntWeapon", 1); // 0 - cF("fWereWolfSecurity", 1); // 0 - cF("fWereWolfPersonality", 1); // 0 - cF("fWereWolfMerchantile", 1); // 0 - cF("fWereWolfHeavyArmor", 1); // 0 - cF("fWereWolfSpear", 1); // 0 - cF("fWereWolfStrength", 150); // same - cF("fWereWolfHealth", 2); // same - cF("fWereWolfMysticism", 1); // 0 - cF("fWereWolfLightArmor", 1); // 0 - cF("fWereWolfWillPower", 1); // 0 - cF("fWereWolfSpeed", 150); // 90 - return false; -} - void GameSetting::load(ESMReader &esm) { assert(mId != ""); - mDirty = false; - // We are apparently allowed to be empty if (!esm.hasMoreSubs()) { @@ -169,17 +41,8 @@ void GameSetting::load(ESMReader &esm) } else esm.fail("Unwanted subrecord type"); - - int spf = esm.getSpecial(); - - // Check if this is one of the mDirty values mentioned above. If it - // is, we set the mDirty flag. This will ONLY work if you've set - // the 'id' string correctly before calling load(). - - if ((spf != SF_Tribunal && isDirtyTribunal()) || (spf != SF_Bloodmoon - && isDirtyBloodmoon())) - mDirty = true; } + void GameSetting::save(ESMWriter &esm) { switch(mType) diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index a3471598c..ab9a9551e 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -25,66 +25,6 @@ struct GameSetting float mF; VarType mType; - // Set to true if this is a 'dirty' entry which should be ignored - bool mDirty; - - /* - These functions check if this game setting is one of the "dirty" - GMST records found in many mods. These are due to a serious bug in - the official TES3 editor. It only occurs in the newer editor - versions that came with Tribunal and Bloodmoon, and only if a - modder tries to make a mod without loading the corresponding - expansion master file. For example, if you have Tribunal installed - and try to make a mod without loading Tribunal.esm, the editor - will insert these GMST records as a replacement for the entries it - cannot find in the ESMs. - - The values of these "dirty" records differ in general from their - values as defined in Tribunal.esm and Bloodmoon.esm, and are - always set to the same "default" values. Most of these values are - nonsensical, ie. changing the "Seller Max" string to "Max Sale", - or change the stats of werewolves to useless values like 1. Some - of them break certain spell effects. - - It is most likely that these values are just leftover values from - an early stage of development that are inserted as default values - by the editor code. They are supposed to be overridden when the - correct esm file is loaded. When it isn't loaded however, you get - stuck with the initial value, and this gets written to every mod - by the editor, for some reason. - - Bethesda themselves have fallen for this bug. If you install both - Tribunal and Bloodmoon, the updated Tribunal.esm will contain the - dirty GMST settings from Bloodmoon, and Bloodmoon.esm will contain - some of the dirty settings from Tribunal. In other words, this bug - affects the game EVEN IF YOU DO NOT USE ANY MODS! - - The guys at Bethesda are well aware of this bug (and many others), - as the mod community and fan base complained about them for a long - time. But unfortunately it was never fixed. - - There are several tools available to help modders remove these - records from their files, but not all modders use them, and they - really shouldn't have to. In this file we choose instead to reject - all the corrupt values at load time. - - These functions checks if the current game setting is one of the - "dirty" ones as described above. TODO: I have not checked this - against other sources yet, do that later. Currently recognizes 22 - values for tribunal and 50 for bloodmoon. Legitimate GMSTs in mods - (setting values other than the default "dirty" ones) are not - affected and will work correctly. - */ - - /* - Checks for dirty tribunal values. These will be ignored if found - in any file except when they are found in "Tribunal.esm". - */ - bool isDirtyTribunal(); - - // Bloodmoon variant - bool isDirtyBloodmoon(); - void load(ESMReader &esm); int getInt() const; From 5a7a8629b6477fb103709f21df394a936b595458 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Mon, 17 Dec 2012 23:20:43 +0100 Subject: [PATCH 164/916] remove unnecessary include directive --- components/esm/loadgmst.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index 6ce20f935..a73095a66 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -2,8 +2,6 @@ #include -#include - #include "esmreader.hpp" #include "esmwriter.hpp" From d348435a1d550fbfd27b4e1fe78a4a39ce56cefe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2012 21:09:57 -0800 Subject: [PATCH 165/916] Improve audio open error message --- apps/openmw/mwsound/soundmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index efdb6f7ea..4ec3dfbb3 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -86,7 +86,7 @@ namespace MWSound { if(devname.empty()) throw; - std::cout <<"Failed to open device \""<init(); Settings::Manager::setString("device", "Sound", ""); } From 20321c45528851c7ab0ea26ab46e3aa33b338025 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2012 21:50:01 -0800 Subject: [PATCH 166/916] Keep track of the actual active sounds --- apps/openmw/mwsound/openal_output.cpp | 52 ++++++++++++++++++++++----- apps/openmw/mwsound/openal_output.hpp | 3 ++ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bfead7843..94499c8fb 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -131,6 +131,8 @@ class OpenAL_SoundStream : public Sound OpenAL_SoundStream(const OpenAL_SoundStream &rhs); OpenAL_SoundStream& operator=(const OpenAL_SoundStream &rhs); + friend class OpenAL_Output; + public: OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder); virtual ~OpenAL_SoundStream(); @@ -232,6 +234,8 @@ OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, Decode mBufferSize = static_cast(sBufferLength*srate); mBufferSize = framesToBytes(mBufferSize, chans, type); + + mOutput.mActiveSounds.push_back(this); } catch(std::exception &e) { @@ -252,6 +256,9 @@ OpenAL_SoundStream::~OpenAL_SoundStream() alGetError(); mDecoder->close(); + + mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(), + mOutput.mActiveSounds.end(), this)); } void OpenAL_SoundStream::play() @@ -402,6 +409,8 @@ protected: ALuint mSource; ALuint mBuffer; + friend class OpenAL_Output; + private: OpenAL_Sound(const OpenAL_Sound &rhs); OpenAL_Sound& operator=(const OpenAL_Sound &rhs); @@ -435,6 +444,7 @@ public: OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf) : mOutput(output), mSource(src), mBuffer(buf) { + mOutput.mActiveSounds.push_back(this); } OpenAL_Sound::~OpenAL_Sound() { @@ -443,6 +453,9 @@ OpenAL_Sound::~OpenAL_Sound() mOutput.mFreeSources.push_back(mSource); mOutput.bufferFinished(mBuffer); + + mOutput.mActiveSounds.erase(std::find(mOutput.mActiveSounds.begin(), + mOutput.mActiveSounds.end(), this)); } void OpenAL_Sound::stop() @@ -597,6 +610,7 @@ void OpenAL_Output::deinit() { mStreamThread->removeAll(); + std::cerr<< "There are "< 0) alDeleteSources(mSources.size(), &mSources[0]); @@ -889,11 +903,22 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 void OpenAL_Output::pauseAllSounds() { - IDVec sources = mSources; - IDDq::const_iterator iter = mFreeSources.begin(); - while(iter != mFreeSources.end()) + IDVec sources; + SoundVec::const_iterator iter = mActiveSounds.begin(); + while(iter != mActiveSounds.end()) { - sources.erase(std::find(sources.begin(), sources.end(), *iter)); + const OpenAL_SoundStream *stream = dynamic_cast(*iter); + if(stream) + { + if(stream->mSource) + sources.push_back(stream->mSource); + } + else + { + const OpenAL_Sound *sound = dynamic_cast(*iter); + if(sound && sound->mSource) + sources.push_back(sound->mSource); + } iter++; } if(sources.size() > 0) @@ -902,11 +927,22 @@ void OpenAL_Output::pauseAllSounds() void OpenAL_Output::resumeAllSounds() { - IDVec sources = mSources; - IDDq::const_iterator iter = mFreeSources.begin(); - while(iter != mFreeSources.end()) + IDVec sources; + SoundVec::const_iterator iter = mActiveSounds.begin(); + while(iter != mActiveSounds.end()) { - sources.erase(std::find(sources.begin(), sources.end(), *iter)); + const OpenAL_SoundStream *stream = dynamic_cast(*iter); + if(stream) + { + if(stream->mSource) + sources.push_back(stream->mSource); + } + else + { + const OpenAL_Sound *sound = dynamic_cast(*iter); + if(sound && sound->mSource) + sources.push_back(sound->mSource); + } iter++; } if(sources.size() > 0) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index ce126035f..41ce56965 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -36,6 +36,9 @@ namespace MWSound uint64_t mBufferCacheMemSize; + typedef std::vector SoundVec; + SoundVec mActiveSounds; + ALuint getBuffer(const std::string &fname); void bufferFinished(ALuint buffer); From dd3e568a003d19ce4717a61cb03b8b194a3b8601 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 17 Dec 2012 23:35:20 -0800 Subject: [PATCH 167/916] Set the sound properties at initialization --- apps/openmw/mwsound/openal_output.cpp | 134 +++++++++++------------- apps/openmw/mwsound/openal_output.hpp | 4 +- apps/openmw/mwsound/sound.hpp | 15 +-- apps/openmw/mwsound/sound_output.hpp | 4 +- apps/openmw/mwsound/soundmanagerimp.cpp | 36 ++----- 5 files changed, 80 insertions(+), 113 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 94499c8fb..824a72299 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -128,13 +128,15 @@ class OpenAL_SoundStream : public Sound volatile bool mIsFinished; + void updateAll(bool local); + OpenAL_SoundStream(const OpenAL_SoundStream &rhs); OpenAL_SoundStream& operator=(const OpenAL_SoundStream &rhs); friend class OpenAL_Output; public: - OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder); + OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags); virtual ~OpenAL_SoundStream(); virtual void stop(); @@ -215,8 +217,9 @@ private: }; -OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder) - : mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true) +OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder, float basevol, float pitch, int flags) + : Sound(Ogre::Vector3(0.0f), 1.0f, basevol, pitch, 1.0f, 1000.0f, flags) + , mOutput(output), mSource(src), mSamplesQueued(0), mDecoder(decoder), mIsFinished(true) { throwALerror(); @@ -324,6 +327,25 @@ double OpenAL_SoundStream::getTimeOffset() return t; } +void OpenAL_SoundStream::updateAll(bool local) +{ + alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); + alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance); + if(local) + { + alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE); + } + else + { + alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f); + alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE); + } + alSourcei(mSource, AL_LOOPING, AL_FALSE); + + update(); +} + void OpenAL_SoundStream::update() { ALfloat gain = mVolume*mBaseVolume; @@ -411,12 +433,14 @@ protected: friend class OpenAL_Output; + void updateAll(bool local); + private: OpenAL_Sound(const OpenAL_Sound &rhs); OpenAL_Sound& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf); + OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags); virtual ~OpenAL_Sound(); virtual void stop(); @@ -434,15 +458,16 @@ class OpenAL_Sound3D : public OpenAL_Sound OpenAL_Sound3D& operator=(const OpenAL_Sound &rhs); public: - OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf) - : OpenAL_Sound(output, src, buf) + OpenAL_Sound3D(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : OpenAL_Sound(output, src, buf, pos, vol, basevol, pitch, mindist, maxdist, flags) { } virtual void update(); }; -OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf) - : mOutput(output), mSource(src), mBuffer(buf) +OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf, const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : Sound(pos, vol, basevol, pitch, mindist, maxdist, flags) + , mOutput(output), mSource(src), mBuffer(buf) { mOutput.mActiveSounds.push_back(this); } @@ -484,10 +509,30 @@ double OpenAL_Sound::getTimeOffset() return t; } +void OpenAL_Sound::updateAll(bool local) +{ + alSourcef(mSource, AL_REFERENCE_DISTANCE, mMinDistance); + alSourcef(mSource, AL_MAX_DISTANCE, mMaxDistance); + if(local) + { + alSourcef(mSource, AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(mSource, AL_SOURCE_RELATIVE, AL_TRUE); + } + else + { + alSourcef(mSource, AL_ROLLOFF_FACTOR, 1.0f); + alSourcei(mSource, AL_SOURCE_RELATIVE, AL_FALSE); + } + alSourcei(mSource, AL_LOOPING, (mFlags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); + + update(); +} + void OpenAL_Sound::update() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; + if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) { gain *= 0.9f; @@ -731,7 +776,7 @@ void OpenAL_Output::bufferFinished(ALuint buf) } -MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, int flags) +MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, float basevol, float pitch, int flags) { boost::shared_ptr sound; ALuint src=0, buf=0; @@ -744,7 +789,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume try { buf = getBuffer(fname); - sound.reset(new OpenAL_Sound(*this, src, buf)); + sound.reset(new OpenAL_Sound(*this, src, buf, Ogre::Vector3(0.0f), vol, basevol, pitch, 1.0f, 1000.0f, flags)); } catch(std::exception &e) { @@ -755,25 +800,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume throw; } - alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f); - alSourcef(src, AL_MAX_DISTANCE, 1000.0f); - alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); - - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) - { - volume *= 0.9f; - pitch *= 0.7f; - } - alSourcef(src, AL_GAIN, volume); - alSourcef(src, AL_PITCH, pitch); - - alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(src, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); - throwALerror(); + sound->updateAll(true); alSourcei(src, AL_BUFFER, buf); alSourcePlay(src); @@ -782,8 +809,8 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume return sound; } -MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch, - float min, float max, int flags) +MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float vol, float basevol, float pitch, + float min, float max, int flags) { boost::shared_ptr sound; ALuint src=0, buf=0; @@ -796,7 +823,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre try { buf = getBuffer(fname); - sound.reset(new OpenAL_Sound3D(*this, src, buf)); + sound.reset(new OpenAL_Sound3D(*this, src, buf, pos, vol, basevol, pitch, min, max, flags)); } catch(std::exception &e) { @@ -807,26 +834,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre throw; } - alSource3f(src, AL_POSITION, pos.x, pos.z, -pos.y); - alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - alSourcef(src, AL_REFERENCE_DISTANCE, min); - alSourcef(src, AL_MAX_DISTANCE, max); - alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f); - - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) - { - volume *= 0.9f; - pitch *= 0.7f; - } - alSourcef(src, AL_GAIN, (pos.squaredDistance(mPos) > max*max) ? - 0.0f : volume); - alSourcef(src, AL_PITCH, pitch); - - alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(src, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); - throwALerror(); + sound->updateAll(false); alSourcei(src, AL_BUFFER, buf); alSourcePlay(src); @@ -850,7 +858,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, fl std::cout <<"Warning: cannot loop stream \""<getName()<<"\""<< std::endl; try { - sound.reset(new OpenAL_SoundStream(*this, src, decoder)); + sound.reset(new OpenAL_SoundStream(*this, src, decoder, volume, pitch, flags)); } catch(std::exception &e) { @@ -858,25 +866,7 @@ MWBase::SoundPtr OpenAL_Output::streamSound(DecoderPtr decoder, float volume, fl throw; } - alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f); - alSourcef(src, AL_MAX_DISTANCE, 1000.0f); - alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); - - if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) - { - volume *= 0.9f; - pitch *= 0.7f; - } - alSourcef(src, AL_GAIN, volume); - alSourcef(src, AL_PITCH, pitch); - - alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(src, AL_LOOPING, AL_FALSE); - throwALerror(); + sound->updateAll(true); sound->play(); return sound; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 41ce56965..29d4102c4 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -48,9 +48,9 @@ namespace MWSound virtual void init(const std::string &devname=""); virtual void deinit(); - virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags); + virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags); virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, - float volume, float pitch, float min, float max, int flags); + float vol, float basevol, float pitch, float min, float max, int flags); virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags); virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index 1b6f50ff4..e76912d67 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -30,13 +30,14 @@ namespace MWSound void setPosition(const Ogre::Vector3 &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } - Sound() : mPos(0.0f, 0.0f, 0.0f) - , mVolume(1.0f) - , mBaseVolume(1.0f) - , mPitch(1.0f) - , mMinDistance(20.0f) /* 1 * min_range_scale */ - , mMaxDistance(12750.0f) /* 255 * max_range_scale */ - , mFlags(MWBase::SoundManager::Play_Normal) + Sound(const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) + : mPos(pos) + , mVolume(vol) + , mBaseVolume(basevol) + , mPitch(pitch) + , mMinDistance(mindist) + , mMaxDistance(maxdist) + , mFlags(flags) { } virtual ~Sound() { } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 1229f87d0..baed39da0 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -24,9 +24,9 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; - virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0; + virtual MWBase::SoundPtr playSound(const std::string &fname, float vol, float basevol, float pitch, int flags) = 0; virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, - float volume, float pitch, float min, float max, int flags) = 0; + float vol, float basevol, float pitch, float min, float max, int flags) = 0; virtual MWBase::SoundPtr streamSound(DecoderPtr decoder, float volume, float pitch, int flags) = 0; virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 4ec3dfbb3..ff10e567a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -221,11 +221,8 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition(); const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); - MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, basevol, 1.0f, - 20.0f, 12750.0f, Play_Normal); - sound->mPos = objpos; - sound->mBaseVolume = basevol; - + MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, + 20.0f, 12750.0f, Play_Normal); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); } catch(std::exception &e) @@ -243,9 +240,7 @@ namespace MWSound float basevol = mMasterVolume * mVoiceVolume; std::string filePath = "Sound/"+filename; - MWBase::SoundPtr sound = mOutput->playSound(filePath, basevol, 1.0f, Play_Normal); - sound->mBaseVolume = basevol; - + MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); } catch(std::exception &e) @@ -282,11 +277,7 @@ namespace MWSound return track; try { - float basevol = mMasterVolume; - - track = mOutput->streamSound(decoder, basevol, 1.0f, Play_NoEnv); - track->mBaseVolume = basevol; - track->mFlags = Play_NoEnv; + track = mOutput->streamSound(decoder, mMasterVolume, 1.0f, Play_NoEnv); } catch(std::exception &e) { @@ -307,14 +298,7 @@ namespace MWSound float min, max; std::string file = lookup(soundId, basevol, min, max); - sound = mOutput->playSound(file, volume*basevol, pitch, mode); - sound->mVolume = volume; - sound->mBaseVolume = basevol; - sound->mPitch = pitch; - sound->mMinDistance = min; - sound->mMaxDistance = max; - sound->mFlags = mode; - + sound = mOutput->playSound(file, volume, basevol, pitch, mode); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception &e) @@ -339,15 +323,7 @@ namespace MWSound const ESM::Position &pos = ptr.getRefData().getPosition();; const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); - sound = mOutput->playSound3D(file, objpos, volume*basevol, pitch, min, max, mode); - sound->mPos = objpos; - sound->mVolume = volume; - sound->mBaseVolume = basevol; - sound->mPitch = pitch; - sound->mMinDistance = min; - sound->mMaxDistance = max; - sound->mFlags = mode; - + sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode); if((mode&Play_NoTrack)) mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); else From 72ffceb2066ef343108676aa404499bb07944f50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2012 00:56:29 -0800 Subject: [PATCH 168/916] Add type flags to the sound play mode --- apps/openmw/mwbase/soundmanager.hpp | 8 ++++++- apps/openmw/mwsound/soundmanagerimp.cpp | 30 +++++++++---------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 8d204bad4..de17f8dc8 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -39,9 +39,15 @@ namespace MWBase Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ - Play_NoTrack = 1<<2 /* (3D only) Play the sound at the given object's position + Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position * but do not keep it updated (the sound will not move with * the object and will not stop when the object is deleted. */ + + Play_TypeSfx = 0, /* Normal SFX sound */ + Play_TypeVoice = 1<<3, /* Voice sound */ + Play_TypeMusic = 1<<4, /* Music track */ + Play_TypeMovie = 1<<5, /* Movie audio track */ + Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeMusic|Play_TypeMovie }; private: diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index ff10e567a..64c3d9903 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -171,9 +171,7 @@ namespace MWSound DecoderPtr decoder = getDecoder(); decoder->open(filename); - mMusic = mOutput->streamSound(decoder, basevol, 1.0f, Play_NoEnv); - mMusic->mBaseVolume = basevol; - mMusic->mFlags = Play_NoEnv; + mMusic = mOutput->streamSound(decoder, basevol, 1.0f, Play_NoEnv|Play_TypeMusic); } catch(std::exception &e) { @@ -222,7 +220,7 @@ namespace MWSound const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f, - 20.0f, 12750.0f, Play_Normal); + 20.0f, 12750.0f, Play_Normal|Play_TypeVoice); mActiveSounds[sound] = std::make_pair(ptr, std::string("_say_sound")); } catch(std::exception &e) @@ -240,7 +238,7 @@ namespace MWSound float basevol = mMasterVolume * mVoiceVolume; std::string filePath = "Sound/"+filename; - MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal); + MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); } catch(std::exception &e) @@ -277,7 +275,7 @@ namespace MWSound return track; try { - track = mOutput->streamSound(decoder, mMasterVolume, 1.0f, Play_NoEnv); + track = mOutput->streamSound(decoder, mMasterVolume, 1.0f, Play_NoEnv|Play_TypeMovie); } catch(std::exception &e) { @@ -296,7 +294,7 @@ namespace MWSound { float basevol = mMasterVolume * mSFXVolume; float min, max; - std::string file = lookup(soundId, basevol, min, max); + std::string file = lookup(soundId, volume, min, max); sound = mOutput->playSound(file, volume, basevol, pitch, mode); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); @@ -309,7 +307,7 @@ namespace MWSound } MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, - float volume, float pitch, int mode) + float volume, float pitch, int mode) { MWBase::SoundPtr sound; if(!mOutput->isInitialized()) @@ -319,7 +317,7 @@ namespace MWSound // Look up the sound in the ESM data float basevol = mMasterVolume * mSFXVolume; float min, max; - std::string file = lookup(soundId, basevol, min, max); + std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition();; const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); @@ -538,18 +536,10 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if(snditer->second.second != "_say_sound") - { - float basevol = mMasterVolume * mSFXVolume; - float min, max; - lookup(snditer->second.second, basevol, min, max); - snditer->first->mBaseVolume = basevol; - } + if((snditer->first->mFlags&MWBase::SoundManager::Play_TypeVoice)) + snditer->first->mBaseVolume = mMasterVolume * mVoiceVolume; else - { - float basevol = mMasterVolume * mVoiceVolume; - snditer->first->mBaseVolume = basevol; - } + snditer->first->mBaseVolume = mMasterVolume * mSFXVolume; snditer->first->update(); snditer++; } From a5356e194efe2af54ea838ca42693eed99f497a5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2012 01:35:20 -0800 Subject: [PATCH 169/916] Allow specifying a type for the playTrack method --- apps/openmw/mwbase/soundmanager.hpp | 9 +++++---- apps/openmw/mwrender/videoplayer.cpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- apps/openmw/mwsound/soundmanagerimp.hpp | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index de17f8dc8..a47b9a6ca 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -34,15 +34,16 @@ namespace MWBase class SoundManager { public: - + /* These must all fit together */ enum PlayMode { Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ - Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position + Play_NoTrack = 1<<2 /* (3D only) Play the sound at the given object's position * but do not keep it updated (the sound will not move with * the object and will not stop when the object is deleted. */ - + }; + enum PlayType { Play_TypeSfx = 0, /* Normal SFX sound */ Play_TypeVoice = 1<<3, /* Voice sound */ Play_TypeMusic = 1<<4, /* Music track */ @@ -97,7 +98,7 @@ namespace MWBase virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0; ///< Stop an actor speaking - virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder) = 0; + virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; ///< Play a 2D audio track, using a custom decoder virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 9c72e9919..e5dee76af 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -869,7 +869,7 @@ int VideoState::stream_open(int stream_index, AVFormatContext *pFormatCtx) this->audio_st = pFormatCtx->streams + stream_index; decoder.reset(new MovieAudioDecoder(this)); - this->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder); + this->AudioTrack = MWBase::Environment::get().getSoundManager()->playTrack(decoder, MWBase::SoundManager::Play_TypeMovie); if(!this->AudioTrack) { avcodec_close((*this->audio_st)->codec); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 64c3d9903..2c4e8eff0 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -268,14 +268,14 @@ namespace MWSound } - MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder) + MWBase::SoundPtr SoundManager::playTrack(const DecoderPtr& decoder, PlayType type) { MWBase::SoundPtr track; if(!mOutput->isInitialized()) return track; try { - track = mOutput->streamSound(decoder, mMasterVolume, 1.0f, Play_NoEnv|Play_TypeMovie); + track = mOutput->streamSound(decoder, mMasterVolume, 1.0f, Play_NoEnv|type); } catch(std::exception &e) { diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 26ff309fb..879110b9f 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -103,7 +103,7 @@ namespace MWSound virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); ///< Stop an actor speaking - virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder); + virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal); From b4e36d4f3104f8eb873c0bc63372cf6a45d9d70a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2012 02:01:04 -0800 Subject: [PATCH 170/916] Add a method to get the volume from the sound type --- apps/openmw/mwsound/sound.hpp | 4 +++ apps/openmw/mwsound/soundmanagerimp.cpp | 42 ++++++++++++++++++------- apps/openmw/mwsound/soundmanagerimp.hpp | 2 ++ 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index e76912d67..8deaf26a6 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -30,6 +30,10 @@ namespace MWSound void setPosition(const Ogre::Vector3 &pos) { mPos = pos; } void setVolume(float volume) { mVolume = volume; } + MWBase::SoundManager::PlayType getPlayType() const + { return (MWBase::SoundManager::PlayType)(mFlags&MWBase::SoundManager::Play_TypeMask); } + + Sound(const Ogre::Vector3& pos, float vol, float basevol, float pitch, float mindist, float maxdist, int flags) : mPos(pos) , mVolume(vol) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 2c4e8eff0..34524ba9a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -137,6 +137,27 @@ namespace MWSound return "Sound/"+snd->mSound; } + // Gets the combined volume settings for the given sound type + float SoundManager::volumeFromType(PlayType type) const + { + float volume = mMasterVolume; + switch(type) + { + case Play_TypeSfx: + volume *= mSFXVolume; + break; + case Play_TypeVoice: + volume *= mVoiceVolume; + break; + case Play_TypeMusic: + case Play_TypeMovie: + volume *= mMusicVolume; + break; + case Play_TypeMask: + break; + } + return volume; + } bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const { @@ -165,13 +186,13 @@ namespace MWSound std::cout <<"Playing "<open(filename); - mMusic = mOutput->streamSound(decoder, basevol, 1.0f, Play_NoEnv|Play_TypeMusic); + mMusic = mOutput->streamSound(decoder, volumeFromType(Play_TypeMusic), + 1.0f, Play_NoEnv|Play_TypeMusic); } catch(std::exception &e) { @@ -214,7 +235,7 @@ namespace MWSound try { // The range values are not tested - float basevol = mMasterVolume * mVoiceVolume; + float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "Sound/"+filename; const ESM::Position &pos = ptr.getRefData().getPosition(); const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); @@ -235,7 +256,7 @@ namespace MWSound return; try { - float basevol = mMasterVolume * mVoiceVolume; + float basevol = volumeFromType(Play_TypeVoice); std::string filePath = "Sound/"+filename; MWBase::SoundPtr sound = mOutput->playSound(filePath, 1.0f, basevol, 1.0f, Play_Normal|Play_TypeVoice); @@ -275,7 +296,7 @@ namespace MWSound return track; try { - track = mOutput->streamSound(decoder, mMasterVolume, 1.0f, Play_NoEnv|type); + track = mOutput->streamSound(decoder, volumeFromType(type), 1.0f, Play_NoEnv|type); } catch(std::exception &e) { @@ -292,7 +313,7 @@ namespace MWSound return sound; try { - float basevol = mMasterVolume * mSFXVolume; + float basevol = volumeFromType((PlayType)(mode&Play_TypeMask)); float min, max; std::string file = lookup(soundId, volume, min, max); @@ -315,7 +336,7 @@ namespace MWSound try { // Look up the sound in the ESM data - float basevol = mMasterVolume * mSFXVolume; + float basevol = volumeFromType((PlayType)(mode&Play_TypeMask)); float min, max; std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition();; @@ -536,16 +557,13 @@ namespace MWSound SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) { - if((snditer->first->mFlags&MWBase::SoundManager::Play_TypeVoice)) - snditer->first->mBaseVolume = mMasterVolume * mVoiceVolume; - else - snditer->first->mBaseVolume = mMasterVolume * mSFXVolume; + snditer->first->mBaseVolume = volumeFromType(snditer->first->getPlayType()); snditer->first->update(); snditer++; } if(mMusic) { - mMusic->mBaseVolume = mMasterVolume * mMusicVolume; + mMusic->mBaseVolume = volumeFromType(mMusic->getPlayType()); mMusic->update(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 879110b9f..f9ceeded6 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -59,6 +59,8 @@ namespace MWSound void updateSounds(float duration); void updateRegionSound(float duration); + float volumeFromType(PlayType type) const; + SoundManager(const SoundManager &rhs); SoundManager& operator=(const SoundManager &rhs); From 1cf019a0070c718976005000af0b50a9ba229af1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 18 Dec 2012 12:36:26 +0100 Subject: [PATCH 171/916] post merge fix --- apps/esmtool/record.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index b5f97e979..a732f1938 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -738,7 +738,6 @@ void Record::print() default: std::cout << "unknown type"; } - std::cout << "\n Dirty: " << mData.mDirty << std::endl; } template<> From 2f8daec379644128e0bec352376029b1f23f26b3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2012 04:19:35 -0800 Subject: [PATCH 172/916] Allow pausing only certain types of sounds --- apps/openmw/mwbase/soundmanager.hpp | 17 +++++++++++------ apps/openmw/mwrender/videoplayer.cpp | 4 ++-- apps/openmw/mwsound/openal_output.cpp | 12 ++++++------ apps/openmw/mwsound/openal_output.hpp | 4 ++-- apps/openmw/mwsound/sound_output.hpp | 4 ++-- apps/openmw/mwsound/soundmanagerimp.cpp | 16 ++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 4 ++-- 7 files changed, 33 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index a47b9a6ca..d804830fa 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -44,10 +44,10 @@ namespace MWBase * the object and will not stop when the object is deleted. */ }; enum PlayType { - Play_TypeSfx = 0, /* Normal SFX sound */ - Play_TypeVoice = 1<<3, /* Voice sound */ - Play_TypeMusic = 1<<4, /* Music track */ - Play_TypeMovie = 1<<5, /* Movie audio track */ + Play_TypeSfx = 1<<3, /* Normal SFX sound */ + Play_TypeVoice = 1<<4, /* Voice sound */ + Play_TypeMusic = 1<<5, /* Music track */ + Play_TypeMovie = 1<<6, /* Movie audio track */ Play_TypeMask = Play_TypeSfx|Play_TypeVoice|Play_TypeMusic|Play_TypeMovie }; @@ -124,10 +124,10 @@ namespace MWBase virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0; ///< Is the given sound currently playing on the given object? - virtual void pauseAllSounds() = 0; + virtual void pauseSounds(int types=Play_TypeMask) = 0; ///< Pauses all currently playing sounds, including music. - virtual void resumeAllSounds() = 0; + virtual void resumeSounds(int types=Play_TypeMask) = 0; ///< Resumes all previously paused sounds. virtual void update(float duration) = 0; @@ -139,6 +139,11 @@ namespace MWBase { return static_cast (a) | static_cast (b); } inline int operator&(SoundManager::PlayMode a, SoundManager::PlayMode b) { return static_cast (a) & static_cast (b); } + + inline int operator|(SoundManager::PlayType a, SoundManager::PlayType b) + { return static_cast (a) | static_cast (b); } + inline int operator&(SoundManager::PlayType a, SoundManager::PlayType b) + { return static_cast (a) & static_cast (b); } } #endif diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index e5dee76af..8e05a4f82 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1092,7 +1092,7 @@ void VideoPlayer::playVideo(const std::string &resourceName) } mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE); - MWBase::Environment::get().getSoundManager()->pauseAllSounds(); + MWBase::Environment::get().getSoundManager()->pauseSounds(); try { mState = new VideoState; @@ -1123,7 +1123,7 @@ void VideoPlayer::close() mState = NULL; } - MWBase::Environment::get().getSoundManager()->resumeAllSounds(); + MWBase::Environment::get().getSoundManager()->resumeSounds(); mRectangle->setVisible(false); mBackgroundRectangle->setVisible(false); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 824a72299..406c1bcca 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -891,7 +891,7 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 } -void OpenAL_Output::pauseAllSounds() +void OpenAL_Output::pauseSounds(int types) { IDVec sources; SoundVec::const_iterator iter = mActiveSounds.begin(); @@ -900,13 +900,13 @@ void OpenAL_Output::pauseAllSounds() const OpenAL_SoundStream *stream = dynamic_cast(*iter); if(stream) { - if(stream->mSource) + if(stream->mSource && (stream->getPlayType()&types)) sources.push_back(stream->mSource); } else { const OpenAL_Sound *sound = dynamic_cast(*iter); - if(sound && sound->mSource) + if(sound && sound->mSource && (sound->getPlayType()&types)) sources.push_back(sound->mSource); } iter++; @@ -915,7 +915,7 @@ void OpenAL_Output::pauseAllSounds() alSourcePausev(sources.size(), &sources[0]); } -void OpenAL_Output::resumeAllSounds() +void OpenAL_Output::resumeSounds(int types) { IDVec sources; SoundVec::const_iterator iter = mActiveSounds.begin(); @@ -924,13 +924,13 @@ void OpenAL_Output::resumeAllSounds() const OpenAL_SoundStream *stream = dynamic_cast(*iter); if(stream) { - if(stream->mSource) + if(stream->mSource && (stream->getPlayType()&types)) sources.push_back(stream->mSource); } else { const OpenAL_Sound *sound = dynamic_cast(*iter); - if(sound && sound->mSource) + if(sound && sound->mSource && (sound->getPlayType()&types)) sources.push_back(sound->mSource); } iter++; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index 29d4102c4..ce35f4e68 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -55,8 +55,8 @@ namespace MWSound virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); - virtual void pauseAllSounds(); - virtual void resumeAllSounds(); + virtual void pauseSounds(int types); + virtual void resumeSounds(int types); OpenAL_Output& operator=(const OpenAL_Output &rhs); OpenAL_Output(const OpenAL_Output &rhs); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index baed39da0..b5ccc946a 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -31,8 +31,8 @@ namespace MWSound virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; - virtual void pauseAllSounds() = 0; - virtual void resumeAllSounds() = 0; + virtual void pauseSounds(int types) = 0; + virtual void resumeSounds(int types) = 0; Sound_Output& operator=(const Sound_Output &rhs); Sound_Output(const Sound_Output &rhs); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 34524ba9a..165d501a2 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -313,11 +313,11 @@ namespace MWSound return sound; try { - float basevol = volumeFromType((PlayType)(mode&Play_TypeMask)); + float basevol = volumeFromType(Play_TypeSfx); float min, max; std::string file = lookup(soundId, volume, min, max); - sound = mOutput->playSound(file, volume, basevol, pitch, mode); + sound = mOutput->playSound(file, volume, basevol, pitch, mode|Play_TypeSfx); mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); } catch(std::exception &e) @@ -336,13 +336,13 @@ namespace MWSound try { // Look up the sound in the ESM data - float basevol = volumeFromType((PlayType)(mode&Play_TypeMask)); + float basevol = volumeFromType(Play_TypeSfx); float min, max; std::string file = lookup(soundId, volume, min, max); const ESM::Position &pos = ptr.getRefData().getPosition();; const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); - sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode); + sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|Play_TypeSfx); if((mode&Play_NoTrack)) mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), soundId); else @@ -423,16 +423,16 @@ namespace MWSound } - void SoundManager::pauseAllSounds() + void SoundManager::pauseSounds(int types) { if(mOutput->isInitialized()) - mOutput->pauseAllSounds(); + mOutput->pauseSounds(types); } - void SoundManager::resumeAllSounds() + void SoundManager::resumeSounds(int types) { if(mOutput->isInitialized()) - mOutput->resumeAllSounds(); + mOutput->resumeSounds(types); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index f9ceeded6..14b8e5cef 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -130,10 +130,10 @@ namespace MWSound virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? - virtual void pauseAllSounds(); + virtual void pauseSounds(int types=Play_TypeMask); ///< Pauses all currently playing sounds, including music. - virtual void resumeAllSounds(); + virtual void resumeSounds(int types=Play_TypeMask); ///< Resumes all previously paused sounds. virtual void update(float duration); From fe36cc1de76724ed540ce16654ad7904c7c43961 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2012 04:35:24 -0800 Subject: [PATCH 173/916] Don't try to resume sound types that aren't paused --- apps/openmw/mwsound/soundmanagerimp.cpp | 9 +++++++++ apps/openmw/mwsound/soundmanagerimp.hpp | 2 ++ 2 files changed, 11 insertions(+) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 165d501a2..d801e6618 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -52,6 +52,7 @@ namespace MWSound , mMusicVolume(1.0f) , mFootstepsVolume(1.0f) , mVoiceVolume(1.0f) + , mPausedSoundTypes(0) { if(!useSound) return; @@ -426,13 +427,21 @@ namespace MWSound void SoundManager::pauseSounds(int types) { if(mOutput->isInitialized()) + { + types &= Play_TypeMask; mOutput->pauseSounds(types); + mPausedSoundTypes |= types; + } } void SoundManager::resumeSounds(int types) { if(mOutput->isInitialized()) + { + types &= types&Play_TypeMask&mPausedSoundTypes; mOutput->resumeSounds(types); + mPausedSoundTypes &= ~types; + } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index 14b8e5cef..d26f51ef0 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -52,6 +52,8 @@ namespace MWSound Ogre::Vector3 mListenerDir; Ogre::Vector3 mListenerUp; + int mPausedSoundTypes; + std::string lookup(const std::string &soundId, float &volume, float &min, float &max); void streamMusicFull(const std::string& filename); From 3b7edae7c3858d83b548c0c140b847d596bb45f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2012 05:19:32 -0800 Subject: [PATCH 174/916] Don't hold a list of all sound sources --- apps/openmw/mwsound/openal_output.cpp | 19 +++++++++++-------- apps/openmw/mwsound/openal_output.hpp | 3 --- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 406c1bcca..67008e2bc 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -637,9 +637,8 @@ void OpenAL_Output::init(const std::string &devname) ALuint src = 0; alGenSources(1, &src); throwALerror(); - mSources.push_back(src); + mFreeSources.push_back(src); } - mFreeSources.insert(mFreeSources.begin(), mSources.begin(), mSources.end()); } catch(std::exception &e) { @@ -655,11 +654,9 @@ void OpenAL_Output::deinit() { mStreamThread->removeAll(); - std::cerr<< "There are "< 0) - alDeleteSources(mSources.size(), &mSources[0]); - mSources.clear(); mBufferRefs.clear(); mUnusedBuffers.clear(); @@ -893,7 +890,7 @@ void OpenAL_Output::updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 void OpenAL_Output::pauseSounds(int types) { - IDVec sources; + std::vector sources; SoundVec::const_iterator iter = mActiveSounds.begin(); while(iter != mActiveSounds.end()) { @@ -912,12 +909,15 @@ void OpenAL_Output::pauseSounds(int types) iter++; } if(sources.size() > 0) + { alSourcePausev(sources.size(), &sources[0]); + throwALerror(); + } } void OpenAL_Output::resumeSounds(int types) { - IDVec sources; + std::vector sources; SoundVec::const_iterator iter = mActiveSounds.begin(); while(iter != mActiveSounds.end()) { @@ -936,7 +936,10 @@ void OpenAL_Output::resumeSounds(int types) iter++; } if(sources.size() > 0) + { alSourcePlayv(sources.size(), &sources[0]); + throwALerror(); + } } diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index ce35f4e68..e240a8b01 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -21,9 +21,6 @@ namespace MWSound ALCdevice *mDevice; ALCcontext *mContext; - typedef std::vector IDVec; - IDVec mSources; - typedef std::deque IDDq; IDDq mFreeSources; IDDq mUnusedBuffers; From 7b2c3e6cd37f597777734a9ddaca20040079d47d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2012 06:01:21 -0800 Subject: [PATCH 175/916] Pass a proper PlayMode enum to playSound and playSound3D --- apps/openmw/mwbase/soundmanager.hpp | 14 ++------------ apps/openmw/mwscript/soundextensions.cpp | 6 ++++-- apps/openmw/mwsound/soundmanagerimp.cpp | 4 ++-- apps/openmw/mwsound/soundmanagerimp.hpp | 4 ++-- apps/openmw/mwworld/weather.cpp | 4 ++-- 5 files changed, 12 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index d804830fa..0c706ab49 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -102,11 +102,11 @@ namespace MWBase ///< Play a 2D audio track, using a custom decoder virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, - int mode=Play_Normal) = 0; + PlayMode mode=Play_Normal) = 0; ///< Play a sound, independently of 3D-position virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, - float volume, float pitch, int mode=Play_Normal) = 0; + float volume, float pitch, PlayMode mode=Play_Normal) = 0; ///< Play a sound from an object virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0; @@ -134,16 +134,6 @@ namespace MWBase virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir, const Ogre::Vector3 &up) = 0; }; - - inline int operator|(SoundManager::PlayMode a, SoundManager::PlayMode b) - { return static_cast (a) | static_cast (b); } - inline int operator&(SoundManager::PlayMode a, SoundManager::PlayMode b) - { return static_cast (a) & static_cast (b); } - - inline int operator|(SoundManager::PlayType a, SoundManager::PlayType b) - { return static_cast (a) | static_cast (b); } - inline int operator&(SoundManager::PlayType a, SoundManager::PlayType b) - { return static_cast (a) & static_cast (b); } } #endif diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index 35e66241e..408a6f29d 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -118,7 +118,8 @@ namespace MWScript std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWBase::SoundManager::Play_Loop : 0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWBase::SoundManager::Play_Loop : + MWBase::SoundManager::Play_Normal); } }; @@ -144,7 +145,8 @@ namespace MWScript Interpreter::Type_Float pitch = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWBase::SoundManager::Play_Loop : 0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWBase::SoundManager::Play_Loop : + MWBase::SoundManager::Play_Normal); } }; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index d801e6618..8a69fc96b 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -307,7 +307,7 @@ namespace MWSound } - MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode) + MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, PlayMode mode) { MWBase::SoundPtr sound; if(!mOutput->isInitialized()) @@ -329,7 +329,7 @@ namespace MWSound } MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, - float volume, float pitch, int mode) + float volume, float pitch, PlayMode mode) { MWBase::SoundPtr sound; if(!mOutput->isInitialized()) diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d26f51ef0..b475449d9 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -110,11 +110,11 @@ namespace MWSound virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); ///< Play a 2D audio track, using a custom decoder - virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal); + virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal); ///< Play a sound, independently of 3D-position virtual MWBase::SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, - float volume, float pitch, int mode=Play_Normal); + float volume, float pitch, PlayMode mode=Play_Normal); ///< Play a sound from an object virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 009b325c0..19bc881f7 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -738,7 +738,7 @@ void WeatherManager::update(float duration) if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) { mSoundsPlaying.push_back(ambientSnd); - MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, true); + MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop); } } @@ -749,7 +749,7 @@ void WeatherManager::update(float duration) if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) { mSoundsPlaying.push_back(rainSnd); - MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, true); + MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop); } } From 1c73a3f2fb967d1edb324668c029746efe8c3a30 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 18 Dec 2012 19:09:08 +0100 Subject: [PATCH 176/916] Revert "remove commandline switch for new game" This reverts commit 86671096ec89960405726594a50e5a7fa787b075. --- apps/openmw/engine.cpp | 10 ++++++++-- apps/openmw/engine.hpp | 4 ++++ apps/openmw/main.cpp | 4 ++++ apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwgui/mainmenu.cpp | 1 - apps/openmw/mwgui/windowmanagerimp.cpp | 12 +++--------- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +--- apps/openmw/mwworld/worldimp.cpp | 8 +++++++- apps/openmw/mwworld/worldimp.hpp | 2 +- 9 files changed, 28 insertions(+), 19 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 08e24b5d6..2299053cd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -125,6 +125,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mFpsLevel(0) , mDebug (false) , mVerboseScripts (false) + , mNewGame (false) , mUseSound (true) , mCompileAll (false) , mScriptContext (0) @@ -236,6 +237,11 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) mVerboseScripts = scriptsVerbosity; } +void OMW::Engine::setNewGame(bool newGame) +{ + mNewGame = newGame; +} + // Initialise and enter main loop. void OMW::Engine::go() @@ -326,13 +332,13 @@ void OMW::Engine::go() // Create the world mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mCfgMgr.getCachePath(), mEncoding, mFallbackMap)); + mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); mEnvironment.setWindowManager (new MWGui::WindowManager( - mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), mCfgMgr.getCachePath ().string(), mScriptConsoleMode)); // Create sound system diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index b13ec4368..57402c91e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -68,6 +68,7 @@ namespace OMW int mFpsLevel; bool mDebug; bool mVerboseScripts; + bool mNewGame; bool mUseSound; bool mCompileAll; std::string mFocusName; @@ -137,6 +138,9 @@ namespace OMW /// Disable or enable all sounds void setSoundUsage(bool soundUsage); + /// Start as a new game. + void setNewGame(bool newGame); + /// Initialise and enter main loop. void go(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 6b31f3ade..0563fdbbb 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -133,6 +133,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-run", bpo::value()->default_value(""), "select a file containing a list of console commands that is executed on startup") + ("new-game", bpo::value()->implicit_value(true) + ->default_value(false), "activate char gen/new game mechanics") + ("fs-strict", bpo::value()->implicit_value(true) ->default_value(false), "strict file system handling (no case folding)") @@ -235,6 +238,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // startup-settings engine.setCell(variables["start"].as()); + engine.setNewGame(variables["new-game"].as()); // other settings engine.setDebugMode(variables["debug"].as()); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 9df75870d..c177912d4 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -79,8 +79,6 @@ namespace MWBase */ virtual void update() = 0; - virtual void newGame() = 0; - virtual void pushGuiMode (MWGui::GuiMode mode) = 0; virtual void popGuiMode() = 0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 0f74f6e14..b19f3de6d 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -94,7 +94,6 @@ namespace MWGui void MainMenu::newGameConfirmed() { MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); - MWBase::Environment::get().getWindowManager ()->newGame (); MWBase::Environment::get().getWorld ()->newGame(); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1f5966f72..627f8f339 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -54,7 +54,7 @@ using namespace MWGui; WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *mOgre, + const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts) : mGuiManager(NULL) , mHud(NULL) @@ -95,8 +95,8 @@ WindowManager::WindowManager( , mGui(NULL) , mGarbageDialogs() , mShown(GW_ALL) - , mAllowed(GW_ALL) - , mRestAllowed(true) + , mAllowed(newGame ? GW_None : GW_ALL) + , mRestAllowed(newGame ? false : true) , mShowFPSLevel(fpsLevel) , mFPS(0.0f) , mTriangleCount(0) @@ -1041,9 +1041,3 @@ void WindowManager::startTraining(MWWorld::Ptr actor) { mTrainingWindow->startTraining(actor); } - -void WindowManager::newGame () -{ - mAllowed = GW_None; - mRestAllowed = false; -} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index db5c22348..2e684b5da 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -74,7 +74,7 @@ namespace MWGui typedef std::pair Faction; typedef std::vector FactionList; - WindowManager(const Compiler::Extensions& extensions, int fpsLevel, + WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts); virtual ~WindowManager(); @@ -86,8 +86,6 @@ namespace MWGui */ virtual void update(); - virtual void newGame(); - virtual void pushGuiMode(GuiMode mode); virtual void popGuiMode(); virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index afcdb8d39..f1fb67632 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -167,7 +167,7 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, + const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), mNewGameStarted(false), @@ -197,6 +197,12 @@ namespace MWWorld // global variables mGlobalVariables = new Globals (mStore); + if (newGame) + { + // set new game mark + mGlobalVariables->setInt ("chargenstate", 1); + } + mGlobalVariables->setInt ("pcrace", 3); mWorldScene = new Scene(*mRendering, mPhysics); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8f89ecff3..a58e70d12 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -95,7 +95,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, + const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, const std::string& encoding, std::map fallbackMap); virtual ~World(); From 64210e6efaf5e536e353d5357900252fab437a34 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 18 Dec 2012 19:09:27 +0100 Subject: [PATCH 177/916] Revert "New Game button" This reverts commit c5dd0e19688b388b6e4e978d5ecf07ec14f5085d. --- apps/openmw/mwbase/world.hpp | 2 -- apps/openmw/mwgui/mainmenu.cpp | 25 +++++-------------------- apps/openmw/mwgui/mainmenu.hpp | 8 +------- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 15 +-------------- apps/openmw/mwworld/worldimp.hpp | 3 --- 6 files changed, 8 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3c707d196..198a20d45 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -82,8 +82,6 @@ namespace MWBase virtual OEngine::Render::Fader* getFader() = 0; ///< \ŧodo remove this function. Rendering details should not be exposed. - virtual void newGame() = 0; - virtual MWWorld::CellStore *getExterior (int x, int y) = 0; virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index b19f3de6d..e98b75e9b 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -6,15 +6,12 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "confirmationdialog.hpp" - namespace MWGui { - MainMenu::MainMenu(MWBase::WindowManager& parWindowManager, int w, int h) + MainMenu::MainMenu(int w, int h) : OEngine::GUI::Layout("openmw_mainmenu.layout") , mButtonBox(0) - , mDialog(parWindowManager) { onResChange(w,h); } @@ -23,7 +20,7 @@ namespace MWGui { setCoord(0,0,w,h); - int height = 64 * 4; + int height = 64 * 3; if (mButtonBox) MyGUI::Gui::getInstance ().destroyWidget(mButtonBox); @@ -36,11 +33,12 @@ namespace MWGui mReturn->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::returnToGame); curH += 64; + + /* mNewGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); - mNewGame->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::newGame); mNewGame->setImageResource ("Menu_NewGame"); curH += 64; -/* + mLoadGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); mLoadGame->setImageResource ("Menu_LoadGame"); curH += 64; @@ -83,17 +81,4 @@ namespace MWGui Ogre::Root::getSingleton ().queueEndRendering (); } - void MainMenu::newGame(MyGUI::Widget* sender) - { - mDialog.open ("#{sNotifyMessage54}"); - mDialog.eventOkClicked.clear(); - mDialog.eventCancelClicked.clear(); - mDialog.eventOkClicked += MyGUI::newDelegate(this, &MainMenu::newGameConfirmed); - } - - void MainMenu::newGameConfirmed() - { - MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); - MWBase::Environment::get().getWorld ()->newGame(); - } } diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index ab48f29d9..fd583d187 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -1,14 +1,12 @@ #include -#include "confirmationdialog.hpp" - namespace MWGui { class MainMenu : public OEngine::GUI::Layout { public: - MainMenu(MWBase::WindowManager& parWindowManager, int w, int h); + MainMenu(int w, int h); void onResChange(int w, int h); @@ -26,10 +24,6 @@ namespace MWGui void returnToGame(MyGUI::Widget* sender); void showOptions(MyGUI::Widget* sender); void exitGame(MyGUI::Widget* sender); - void newGame(MyGUI::Widget* sender); - void newGameConfirmed(); - - ConfirmationDialog mDialog; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 627f8f339..373546aa8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -139,7 +139,7 @@ WindowManager::WindowManager( mDragAndDrop->mDraggedWidget = 0; mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - mMenu = new MainMenu(*this, w,h); + mMenu = new MainMenu(w,h); mMap = new MapWindow(*this, cacheDir); mStatsWindow = new StatsWindow(*this); mConsole = new Console(w,h, consoleOnlyScripts); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f1fb67632..8eb121d37 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -170,7 +170,7 @@ namespace MWWorld const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), - mSky (true), mCells (mStore, mEsm), mNewGameStarted(false), + mSky (true), mCells (mStore, mEsm), mNumFacing(0) { mPhysics = new PhysicsSystem(renderer); @@ -1015,12 +1015,6 @@ namespace MWWorld } } } - - if (mNewGameStarted) - { - playVideo ("mw_intro.bik"); - mNewGameStarted = false; - } } bool World::isCellExterior() const @@ -1302,11 +1296,4 @@ namespace MWWorld { mRendering->stopVideo(); } - - void World::newGame () - { - // set new game mark - mGlobalVariables->setInt ("chargenstate", 1); - mNewGameStarted = true; // in order to play the intro video at the end of the next frame - } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a58e70d12..1c1352913 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -60,7 +60,6 @@ namespace MWWorld MWWorld::Globals *mGlobalVariables; MWWorld::PhysicsSystem *mPhysics; bool mSky; - bool mNewGameStarted; Cells mCells; @@ -103,8 +102,6 @@ namespace MWWorld virtual OEngine::Render::Fader* getFader(); ///< \ŧodo remove this function. Rendering details should not be exposed. - virtual void newGame(); - virtual CellStore *getExterior (int x, int y); virtual CellStore *getInterior (const std::string& name); From 85850c7440d54d612c9ab8fd9026a1ae5c06f095 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 18 Dec 2012 10:22:40 -0800 Subject: [PATCH 178/916] Fix DEFAULT_OUTPUT declaration --- apps/openmw/mwsound/openal_output.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index e240a8b01..02706b50c 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -70,7 +70,7 @@ namespace MWSound friend class SoundManager; }; #ifndef DEFAULT_OUTPUT -#define DEFAULT_OUTPUT (::MWSound::OpenAL_Output) +#define DEFAULT_OUTPUT(x) ::MWSound::OpenAL_Output((x)) #endif } From f2c6907244a25949094dfe67529ec53992e44a91 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 20 Dec 2012 23:16:34 +0000 Subject: [PATCH 179/916] Added in text escape sequences for dialogue, messageboxes and books. builtins are placeholders, global variables work --- apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 +- apps/openmw/mwgui/formatting.cpp | 12 ++ apps/openmw/mwscript/interpretercontext.cpp | 14 ++ apps/openmw/mwscript/interpretercontext.hpp | 4 + apps/openmw/mwworld/globals.cpp | 11 + apps/openmw/mwworld/globals.hpp | 3 + apps/openmw/mwworld/worldimp.cpp | 5 + apps/openmw/mwworld/worldimp.hpp | 2 + components/CMakeLists.txt | 2 +- components/interpreter/context.hpp | 4 + components/interpreter/defines.cpp | 200 ++++++++++++++++++ components/interpreter/defines.hpp | 12 ++ components/interpreter/miscopcodes.hpp | 4 +- 14 files changed, 282 insertions(+), 5 deletions(-) create mode 100644 components/interpreter/defines.cpp create mode 100644 components/interpreter/defines.hpp diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 40ebde246..0be732790 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -133,6 +133,8 @@ namespace MWBase virtual char getGlobalVariableType (const std::string& name) const = 0; ///< Return ' ', if there is no global variable with this name. + + virtual std::vector getGlobals () const = 0; virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; ///< Return a pointer to a liveCellRef with the given name. diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 80316c0f5..26d5af202 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -155,7 +156,9 @@ namespace MWDialogue } parseText (info->mResponse); - win->addText (info->mResponse); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); mLastTopic = it->mId; mLastDialogue = *info; @@ -267,7 +270,8 @@ namespace MWDialogue else win->addTitle (topic); - win->addText (info->mResponse); + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); @@ -411,7 +415,9 @@ namespace MWDialogue mIsInChoice = false; std::string text = info->mResponse; parseText (text); - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (text); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); executeScript (info->mResultScript); mLastTopic = mLastTopic; mLastDialogue = *info; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 53c23c25d..273034edd 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -1,5 +1,10 @@ #include "formatting.hpp" +#include + +#include "../mwscript/interpretercontext.hpp" +#include "../mwworld/ptr.hpp" + #include #include @@ -68,6 +73,9 @@ std::vector BookTextParser::split(std::string text, const int width { std::vector result; + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesDialog(text, interpreterContext); + boost::algorithm::replace_all(text, "
", "\n"); boost::algorithm::replace_all(text, "

", "\n\n"); @@ -167,6 +175,10 @@ std::vector BookTextParser::split(std::string text, const int width MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesDialog(text, interpreterContext); + + mParent = parent; mWidth = width; mHeight = 0; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 577ad008f..4ea984f9c 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -174,6 +174,20 @@ namespace MWScript MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat = value; } + std::vector InterpreterContext::getGlobals () const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + return world->getGlobals(); + + } + + char InterpreterContext::getGlobalType (const std::string& name) const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + return world->getGlobalVariableType(name); + } + + bool InterpreterContext::isScriptRunning (const std::string& name) const { return MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name); diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 6d97f7949..15578aa24 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -75,6 +75,10 @@ namespace MWScript virtual void setGlobalLong (const std::string& name, int value); virtual void setGlobalFloat (const std::string& name, float value); + + virtual std::vector getGlobals () const; + + virtual char getGlobalType (const std::string& name) const; virtual bool isScriptRunning (const std::string& name) const; diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 76dede5a3..f010661b9 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -7,6 +7,17 @@ namespace MWWorld { + std::vector Globals::getGlobals () const + { + std::vector retval; + Collection::const_iterator it; + for(it = mVariables.begin(); it != mVariables.end(); ++it){ + retval.push_back(it->first); + } + + return retval; + } + Globals::Collection::const_iterator Globals::find (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index c7aee5f93..681bd560e 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -1,6 +1,7 @@ #ifndef GAME_MWWORLD_GLOBALS_H #define GAME_MWWORLD_GLOBALS_H +#include #include #include @@ -53,6 +54,8 @@ namespace MWWorld char getType (const std::string& name) const; ///< If there is no global variable with this name, ' ' is returned. + + std::vector getGlobals () const; }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f0b2efcec..88ad917c3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -296,6 +296,11 @@ namespace MWWorld return mGlobalVariables->getType (name); } + std::vector World::getGlobals () const + { + return mGlobalVariables->getGlobals(); + } + Ptr World::getPtr (const std::string& name, bool activeOnly) { // the player is always in an active cell. diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0962c292c..15b13256a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -153,6 +153,8 @@ namespace MWWorld virtual char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name. + + virtual std::vector getGlobals () const; virtual Ptr getPtr (const std::string& name, bool activeOnly); ///< Return a pointer to a liveCellRef with the given name. diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 29d6f46cd..bff99a69c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -59,7 +59,7 @@ add_component_dir (compiler add_component_dir (interpreter context controlopcodes genericopcodes installopcodes interpreter localopcodes mathopcodes - miscopcodes opcodes runtime scriptopcodes spatialopcodes types + miscopcodes opcodes runtime scriptopcodes spatialopcodes types defines ) include_directories(${BULLET_INCLUDE_DIRS}) diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 4221da36e..2cfc1c03d 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -49,6 +49,10 @@ namespace Interpreter virtual void setGlobalFloat (const std::string& name, float value) = 0; + virtual std::vector getGlobals () const = 0; + + virtual char getGlobalType (const std::string& name) const = 0; + virtual bool isScriptRunning (const std::string& name) const = 0; virtual void startScript (const std::string& name) = 0; diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp new file mode 100644 index 000000000..d5e3e3d0d --- /dev/null +++ b/components/interpreter/defines.cpp @@ -0,0 +1,200 @@ +#include "defines.hpp" + +#include +#include +#include +#include + +namespace Interpreter{ + + bool Check(const std::string str, const std::string escword, unsigned int* i, unsigned int* start){ + bool retval = str.find(escword) == 0; + if(retval){ + (*i) += escword.length(); + (*start) = (*i) + 1; + } + return retval; + } + + std::vector globals; + + bool longerStr(const std::string a, const std::string b){ + return a.length() > b.length(); + } + + std::string fixDefinesReal(std::string text, char eschar, Context& context){ + + unsigned int start = 0; + std::string retval = ""; + for(unsigned int i = 0; i < text.length(); i++){ + if(text[i] == eschar){ + retval += text.substr(start, i - start); + std::string temp = text.substr(i+1, 100); + transform(temp.begin(), temp.end(), temp.begin(), ::tolower); + + bool found; + + if( (found = Check(temp, "actionslideright", &i, &start))){ + retval += "PLACEHOLDER_ACTION_SLIDE_RIGHT"; + } + else if((found = Check(temp, "actionreadymagic", &i, &start))){ + retval += "PLACEHOLDER_ACTION_READY_MAGIC"; + } + else if((found = Check(temp, "actionprevweapon", &i, &start))){ + retval += "PLACEHOLDER_ACTION_PREV_WEAPON"; + } + else if((found = Check(temp, "actionnextweapon", &i, &start))){ + retval += "PLACEHOLDER_ACTION_PREV_WEAPON"; + } + else if((found = Check(temp, "actiontogglerun", &i, &start))){ + retval += "PLACEHOLDER_ACTION_TOGGLE_RUN"; + } + else if((found = Check(temp, "actionslideleft", &i, &start))){ + retval += "PLACEHOLDER_ACTION_TOGGLE_RUN"; + } + else if((found = Check(temp, "actionreadyitem", &i, &start))){ + retval += "PLACEHOLDER_ACTION_READY_ITEM"; + } + else if((found = Check(temp, "actionprevspell", &i, &start))){ + retval += "PLACEHOLDER_ACTION_PREV_SPELL"; + } + else if((found = Check(temp, "actionnextspell", &i, &start))){ + retval += "PLACEHOLDER_ACTION_NEXT_SPELL"; + } + else if((found = Check(temp, "actionrestmenu", &i, &start))){ + retval += "PLACEHOLDER_ACTION_REST_MENU"; + } + else if((found = Check(temp, "actionmenumode", &i, &start))){ + retval += "PLACEHOLDER_ACTION_MENU_MODE"; + } + else if((found = Check(temp, "actionactivate", &i, &start))){ + retval += "PLACEHOLDER_ACTION_ACTIVATE"; + } + else if((found = Check(temp, "actionjournal", &i, &start))){ + retval += "PLACEHOLDER_ACTION_JOURNAL"; + } + else if((found = Check(temp, "actionforward", &i, &start))){ + retval += "PLACEHOLDER_ACTION_FORWARD"; + } + else if((found = Check(temp, "pccrimelevel", &i, &start))){ + retval += "PLACEHOLDER_PC_CRIME_LEVEL"; + } + else if((found = Check(temp, "actioncrouch", &i, &start))){ + retval += "PLACEHOLDER_ACTION_CROUCH"; + } + else if((found = Check(temp, "actionjump", &i, &start))){ + retval += "PLACEHOLDER_ACTION_JUMP"; + } + else if((found = Check(temp, "actionback", &i, &start))){ + retval += "PLACEHOLDER_ACTION_BACK"; + } + else if((found = Check(temp, "actionuse", &i, &start))){ + retval += "PLACEHOLDER_ACTION_USE"; + } + else if((found = Check(temp, "actionrun", &i, &start))){ + retval += "PLACEHOLDER_ACTION_RUN"; + } + else if((found = Check(temp, "pcclass", &i, &start))){ + retval += "PLACEHOLDER_PC_CLASS"; + } + else if((found = Check(temp, "pcrace", &i, &start))){ + retval += "PLACEHOLDER_PC_RACE"; + } + else if((found = Check(temp, "pcname", &i, &start))){ + retval += "PLACEHOLDER_PC_NAME"; + } + else if((found = Check(temp, "cell", &i, &start))){ + retval += "PLACEHOLDER_CELL"; + } + + else if(eschar == '%'){ // In Dialogue, not messagebox + if( (found = Check(temp, "faction", &i, &start))){ + retval += "PLACEHOLDER_FACTION"; + } + else if((found = Check(temp, "nextpcrank", &i, &start))){ + retval += "PLACEHOLDER_NEXT_PC_RANK"; + } + else if((found = Check(temp, "pcnextrank", &i, &start))){ + retval += "PLACEHOLDER_PC_NEXT_RANK"; + } + else if((found = Check(temp, "pcrank", &i, &start))){ + retval += "PLACEHOLDER_PC_RANK"; + } + else if((found = Check(temp, "rank", &i, &start))){ + retval += "PLACEHOLDER_RANK"; + } + + else if((found = Check(temp, "class", &i, &start))){ + retval += "PLACEHOLDER_CLASS"; + } + else if((found = Check(temp, "race", &i, &start))){ + retval += "PLACEHOLDER_RACE"; + } + else if((found = Check(temp, "name", &i, &start))){ + retval += "PLACEHOLDER_NAME"; + } + } + else if(eschar == '^') { // In messagebox, not dialogue + + /* empty in messageboxes */ + if( (found = Check(temp, "faction", &i, &start))); + else if((found = Check(temp, "nextpcrank", &i, &start))); + else if((found = Check(temp, "pcnextrank", &i, &start))); + else if((found = Check(temp, "pcrank", &i, &start))); + else if((found = Check(temp, "rank", &i, &start))); + + /* uses pc in messageboxes */ + else if((found = Check(temp, "class", &i, &start))){ + retval += "PLACEHOLDER_CLASS"; + } + else if((found = Check(temp, "race", &i, &start))){ + retval += "PLACEHOLDER_RACE"; + } + else if((found = Check(temp, "name", &i, &start))){ + retval += "PLACEHOLDER_NAME"; + } + } + + /* Not a builtin, try global variables */ + if(!found){ + /* if list of globals is empty, grab it and sort it by descending string length */ + if(globals.empty()){ + globals = context.getGlobals(); + sort(globals.begin(), globals.end(), longerStr); + } + + for(unsigned int j = 0; j < globals.size(); j++){ + if((found = Check(temp, globals[j], &i, &start))){ + char type = context.getGlobalType(globals[j]); + + switch(type){ + case 's': retval += std::to_string(context.getGlobalShort(globals[j])); break; + case 'l': retval += std::to_string(context.getGlobalLong(globals[j])); break; + case 'f': retval += std::to_string(context.getGlobalFloat(globals[j])); break; + } + break; + } + } + } + + /* Not found */ + if(!found){ + /* leave unmodified */ + i += 1; + start = i; + retval += eschar; + } + } + } + retval += text.substr(start, text.length() - start); + return retval; + } + + std::string fixDefinesDialog(std::string text, Context& context){ + return fixDefinesReal(text, '%', context); + } + + std::string fixDefinesMsgBox(std::string text, Context& context){ + return fixDefinesReal(text, '^', context); + } +} diff --git a/components/interpreter/defines.hpp b/components/interpreter/defines.hpp new file mode 100644 index 000000000..731284661 --- /dev/null +++ b/components/interpreter/defines.hpp @@ -0,0 +1,12 @@ +#ifndef GAME_MWMECHANICS_DEFINES_H +#define GAME_MWMECHANICS_DEFINES_H + +#include +#include "context.hpp" + +namespace Interpreter{ + std::string fixDefinesDialog(std::string text, Context& context); + std::string fixDefinesMsgBox(std::string text, Context& context); +} + +#endif diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 37c38fc30..1b4c823a0 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -10,6 +10,7 @@ #include "opcodes.hpp" #include "runtime.hpp" +#include "defines.hpp" namespace Interpreter { @@ -69,7 +70,8 @@ namespace Interpreter } } } - + + formattedMessage = fixDefinesMsgBox(formattedMessage, runtime.getContext()); return formattedMessage; } From 8ac8fdff47b0fdf2523f8dadc2b370994b394f4d Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Fri, 21 Dec 2012 18:09:31 +0000 Subject: [PATCH 180/916] implemented all text defines except a few for keybindings that don't exist yet --- apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwscript/interpretercontext.cpp | 129 ++++++++++++++++++++ apps/openmw/mwscript/interpretercontext.hpp | 26 ++++ apps/openmw/mwworld/worldimp.cpp | 38 ++++++ apps/openmw/mwworld/worldimp.hpp | 2 + components/interpreter/context.hpp | 26 ++++ components/interpreter/defines.cpp | 58 ++++----- components/interpreter/defines.hpp | 4 +- 8 files changed, 254 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 0be732790..cc625b306 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -136,6 +136,8 @@ namespace MWBase virtual std::vector getGlobals () const = 0; + virtual std::string getCurrentCellName() const = 0; + virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 4ea984f9c..cb0e4a7f9 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -11,10 +11,13 @@ #include "../mwbase/world.hpp" #include "../mwbase/scriptmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/inputmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "locals.hpp" #include "globalscripts.hpp" @@ -186,7 +189,133 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); return world->getGlobalVariableType(name); } + + std::string InterpreterContext::getActionBinding(const std::string& action) const + { + std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) + { + std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); + if(desc == "") + continue; + if(desc == action) + return MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + } + + return "None"; + } + + std::string InterpreterContext::getNPCName() const + { + ESM::NPC npc = *mReference.get()->mBase; + return npc.mName; + } + + std::string InterpreterContext::getNPCRace() const + { + ESM::NPC npc = *mReference.get()->mBase; + return npc.mRace; + } + + std::string InterpreterContext::getNPCClass() const + { + ESM::NPC npc = *mReference.get()->mBase; + return npc.mClass; + } + + std::string InterpreterContext::getNPCFaction() const + { + ESM::NPC npc = *mReference.get()->mBase; + return npc.mFaction; + } + + std::string InterpreterContext::getNPCRank() const + { + std::map ranks = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks(); + std::map::const_iterator it = ranks.begin(); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::Faction *faction = store.get().find(it->first); + + return faction->mRanks[it->second]; + } + + std::string InterpreterContext::getPCName() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + ESM::NPC player = *world->getPlayer().getPlayer().get()->mBase; + return player.mName; + } + + std::string InterpreterContext::getPCRace() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + ESM::NPC player = *world->getPlayer().getPlayer().get()->mBase; + return player.mRace; + } + + std::string InterpreterContext::getPCClass() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + ESM::NPC player = *world->getPlayer().getPlayer().get()->mBase; + return player.mClass; + } + + std::string InterpreterContext::getPCRank() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first; + + std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); + std::map::const_iterator it = ranks.begin(); + + const MWWorld::ESMStore &store = world->getStore(); + const ESM::Faction *faction = store.get().find(factionId); + + if(it->second < 0 || it->second > 9) // there are only 10 ranks + return ""; + + return faction->mRanks[it->second]; + } + + std::string InterpreterContext::getPCNextRank() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first; + + std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); + std::map::const_iterator it = ranks.begin(); + + const MWWorld::ESMStore &store = world->getStore(); + const ESM::Faction *faction = store.get().find(factionId); + + if(it->second < 0 || it->second > 9) + return ""; + + if(it->second <= 8) // If player is at max rank, there is no next rank + return faction->mRanks[it->second + 1]; + else + return faction->mRanks[it->second]; + } + + int InterpreterContext::getPCBounty() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + return MWWorld::Class::get (player).getNpcStats (player).getBounty(); + } + + std::string InterpreterContext::getCurrentCellName() const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + return world->getCurrentCellName(); + } bool InterpreterContext::isScriptRunning (const std::string& name) const { diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 15578aa24..f0b2758d9 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -79,6 +79,32 @@ namespace MWScript virtual std::vector getGlobals () const; virtual char getGlobalType (const std::string& name) const; + + virtual std::string getActionBinding(const std::string& action) const; + + virtual std::string getNPCName() const; + + virtual std::string getNPCRace() const; + + virtual std::string getNPCClass() const; + + virtual std::string getNPCFaction() const; + + virtual std::string getNPCRank() const; + + virtual std::string getPCName() const; + + virtual std::string getPCRace() const; + + virtual std::string getPCClass() const; + + virtual std::string getPCRank() const; + + virtual std::string getPCNextRank() const; + + virtual int getPCBounty() const; + + virtual std::string getCurrentCellName() const; virtual bool isScriptRunning (const std::string& name) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 88ad917c3..343b5dcfc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -300,6 +300,44 @@ namespace MWWorld { return mGlobalVariables->getGlobals(); } + + std::string World::getCurrentCellName () const + { + std::string name; + + Ptr::CellStore *cell = mWorldScene->getCurrentCell(); + if (cell->mCell->isExterior()) + { + if (cell->mCell->mName != "") + { + name = cell->mCell->mName; + } + else + { + const ESM::Region* region = + MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); + if (region) + name = region->mName; + else + { + const ESM::GameSetting *setting = + MWBase::Environment::get().getWorld()->getStore().get().search("sDefaultCellname"); + + if (setting && setting->mType == ESM::VT_String) + name = setting->getString(); + else + name = "Wilderness"; + } + + } + } + else + { + name = cell->mCell->mName; + } + + return name; + } Ptr World::getPtr (const std::string& name, bool activeOnly) { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 15b13256a..ba90dd403 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -155,6 +155,8 @@ namespace MWWorld ///< Return ' ', if there is no global variable with this name. virtual std::vector getGlobals () const; + + virtual std::string getCurrentCellName () const; virtual Ptr getPtr (const std::string& name, bool activeOnly); ///< Return a pointer to a liveCellRef with the given name. diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 2cfc1c03d..bdba7b6af 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -53,6 +53,32 @@ namespace Interpreter virtual char getGlobalType (const std::string& name) const = 0; + virtual std::string getActionBinding(const std::string& action) const = 0; + + virtual std::string getNPCName() const = 0; + + virtual std::string getNPCRace() const = 0; + + virtual std::string getNPCClass() const = 0; + + virtual std::string getNPCFaction() const = 0; + + virtual std::string getNPCRank() const = 0; + + virtual std::string getPCName() const = 0; + + virtual std::string getPCRace() const = 0; + + virtual std::string getPCClass() const = 0; + + virtual std::string getPCRank() const = 0; + + virtual std::string getPCNextRank() const = 0; + + virtual int getPCBounty() const = 0; + + virtual std::string getCurrentCellName() const = 0; + virtual bool isScriptRunning (const std::string& name) const = 0; virtual void startScript (const std::string& name) = 0; diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index d5e3e3d0d..bd355fd7c 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -35,10 +35,10 @@ namespace Interpreter{ bool found; if( (found = Check(temp, "actionslideright", &i, &start))){ - retval += "PLACEHOLDER_ACTION_SLIDE_RIGHT"; + retval += context.getActionBinding("#{sRight}"); } else if((found = Check(temp, "actionreadymagic", &i, &start))){ - retval += "PLACEHOLDER_ACTION_READY_MAGIC"; + retval += context.getActionBinding("#{sReady_Magic}"); } else if((found = Check(temp, "actionprevweapon", &i, &start))){ retval += "PLACEHOLDER_ACTION_PREV_WEAPON"; @@ -47,13 +47,13 @@ namespace Interpreter{ retval += "PLACEHOLDER_ACTION_PREV_WEAPON"; } else if((found = Check(temp, "actiontogglerun", &i, &start))){ - retval += "PLACEHOLDER_ACTION_TOGGLE_RUN"; + retval += context.getActionBinding("#{sAuto_Run}"); } else if((found = Check(temp, "actionslideleft", &i, &start))){ - retval += "PLACEHOLDER_ACTION_TOGGLE_RUN"; + retval += context.getActionBinding("#{sLeft}"); } else if((found = Check(temp, "actionreadyitem", &i, &start))){ - retval += "PLACEHOLDER_ACTION_READY_ITEM"; + retval += context.getActionBinding("#{sReady_Weapon}"); } else if((found = Check(temp, "actionprevspell", &i, &start))){ retval += "PLACEHOLDER_ACTION_PREV_SPELL"; @@ -62,31 +62,31 @@ namespace Interpreter{ retval += "PLACEHOLDER_ACTION_NEXT_SPELL"; } else if((found = Check(temp, "actionrestmenu", &i, &start))){ - retval += "PLACEHOLDER_ACTION_REST_MENU"; + retval += context.getActionBinding("#{sRestKey}"); } else if((found = Check(temp, "actionmenumode", &i, &start))){ - retval += "PLACEHOLDER_ACTION_MENU_MODE"; + retval += context.getActionBinding("#{sJournal}"); } else if((found = Check(temp, "actionactivate", &i, &start))){ - retval += "PLACEHOLDER_ACTION_ACTIVATE"; + retval += context.getActionBinding("#{sActivate}"); } else if((found = Check(temp, "actionjournal", &i, &start))){ - retval += "PLACEHOLDER_ACTION_JOURNAL"; + retval += context.getActionBinding("#{sJournal}"); } else if((found = Check(temp, "actionforward", &i, &start))){ - retval += "PLACEHOLDER_ACTION_FORWARD"; + retval += context.getActionBinding("#{sForward}"); } else if((found = Check(temp, "pccrimelevel", &i, &start))){ - retval += "PLACEHOLDER_PC_CRIME_LEVEL"; + retval += std::to_string(context.getPCBounty()); } else if((found = Check(temp, "actioncrouch", &i, &start))){ - retval += "PLACEHOLDER_ACTION_CROUCH"; + retval += context.getActionBinding("#{sCrouch_Sneak}"); } else if((found = Check(temp, "actionjump", &i, &start))){ - retval += "PLACEHOLDER_ACTION_JUMP"; + retval += context.getActionBinding("#{sJump}"); } else if((found = Check(temp, "actionback", &i, &start))){ - retval += "PLACEHOLDER_ACTION_BACK"; + retval += context.getActionBinding("#{sBack}"); } else if((found = Check(temp, "actionuse", &i, &start))){ retval += "PLACEHOLDER_ACTION_USE"; @@ -95,43 +95,43 @@ namespace Interpreter{ retval += "PLACEHOLDER_ACTION_RUN"; } else if((found = Check(temp, "pcclass", &i, &start))){ - retval += "PLACEHOLDER_PC_CLASS"; + retval += context.getPCClass(); } else if((found = Check(temp, "pcrace", &i, &start))){ - retval += "PLACEHOLDER_PC_RACE"; + retval += context.getPCRace(); } else if((found = Check(temp, "pcname", &i, &start))){ - retval += "PLACEHOLDER_PC_NAME"; + retval += context.getPCName(); } else if((found = Check(temp, "cell", &i, &start))){ - retval += "PLACEHOLDER_CELL"; + retval += context.getCurrentCellName(); } else if(eschar == '%'){ // In Dialogue, not messagebox if( (found = Check(temp, "faction", &i, &start))){ - retval += "PLACEHOLDER_FACTION"; + retval += context.getNPCFaction(); } else if((found = Check(temp, "nextpcrank", &i, &start))){ - retval += "PLACEHOLDER_NEXT_PC_RANK"; + retval += context.getPCNextRank(); } else if((found = Check(temp, "pcnextrank", &i, &start))){ - retval += "PLACEHOLDER_PC_NEXT_RANK"; + retval += context.getPCNextRank(); } else if((found = Check(temp, "pcrank", &i, &start))){ - retval += "PLACEHOLDER_PC_RANK"; + retval += context.getPCRank(); } else if((found = Check(temp, "rank", &i, &start))){ - retval += "PLACEHOLDER_RANK"; + retval += context.getNPCRank(); } else if((found = Check(temp, "class", &i, &start))){ - retval += "PLACEHOLDER_CLASS"; + retval += context.getNPCClass(); } else if((found = Check(temp, "race", &i, &start))){ - retval += "PLACEHOLDER_RACE"; + retval += context.getNPCRace(); } else if((found = Check(temp, "name", &i, &start))){ - retval += "PLACEHOLDER_NAME"; + retval += context.getNPCName(); } } else if(eschar == '^') { // In messagebox, not dialogue @@ -145,13 +145,13 @@ namespace Interpreter{ /* uses pc in messageboxes */ else if((found = Check(temp, "class", &i, &start))){ - retval += "PLACEHOLDER_CLASS"; + retval += context.getPCClass(); } else if((found = Check(temp, "race", &i, &start))){ - retval += "PLACEHOLDER_RACE"; + retval += context.getPCRace(); } else if((found = Check(temp, "name", &i, &start))){ - retval += "PLACEHOLDER_NAME"; + retval += context.getPCName(); } } diff --git a/components/interpreter/defines.hpp b/components/interpreter/defines.hpp index 731284661..4cfba21ea 100644 --- a/components/interpreter/defines.hpp +++ b/components/interpreter/defines.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_MWMECHANICS_DEFINES_H -#define GAME_MWMECHANICS_DEFINES_H +#ifndef INTERPRETER_DEFINES_H_INCLUDED +#define INTERPRETER_DEFINES_H_INCLUDED #include #include "context.hpp" From 74ae47978009d6a0b187284615bc924e4c9ad971 Mon Sep 17 00:00:00 2001 From: lazydev Date: Sun, 23 Dec 2012 23:23:24 +0400 Subject: [PATCH 181/916] Cell names localization fix --- apps/esmtool/esmtool.cpp | 22 ++-- apps/launcher/model/datafilesmodel.cpp | 4 +- apps/openmw/engine.cpp | 9 +- apps/openmw/engine.hpp | 4 +- apps/openmw/main.cpp | 17 +-- apps/openmw/mwclass/door.cpp | 56 ++++++---- apps/openmw/mwclass/door.hpp | 3 + apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwgui/map_window.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 28 +++-- apps/openmw/mwgui/windowmanagerimp.hpp | 5 +- apps/openmw/mwworld/esmstore.hpp | 8 +- apps/openmw/mwworld/recordcmp.hpp | 56 +--------- apps/openmw/mwworld/store.hpp | 26 ++--- apps/openmw/mwworld/worldimp.cpp | 39 ++----- apps/openmw/mwworld/worldimp.hpp | 6 +- components/CMakeLists.txt | 4 + components/esm/esmreader.cpp | 16 +-- components/esm/esmreader.hpp | 2 +- components/misc/stringops.hpp | 50 +++++++++ components/to_utf8/to_utf8.cpp | 20 ++++ components/to_utf8/to_utf8.hpp | 3 + .../translation_data/translation_data.cpp | 104 ++++++++++++++++++ .../translation_data/translation_data.hpp | 36 ++++++ 24 files changed, 339 insertions(+), 183 deletions(-) create mode 100644 components/translation_data/translation_data.cpp create mode 100644 components/translation_data/translation_data.hpp diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 4f6d9dbfc..963656af5 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -59,7 +59,7 @@ struct Arguments std::string outname; std::vector types; - + ESMData data; ESM::ESMReader reader; ESM::ESMWriter writer; @@ -74,7 +74,7 @@ bool parseOptions (int argc, char** argv, Arguments &info) ("version,v", "print version information and quit.") ("raw,r", "Show an unformatted list of all records and subrecords.") // The intention is that this option would interact better - // with other modes including clone, dump, and raw. + // with other modes including clone, dump, and raw. ("type,t", bpo::value< std::vector >(), "Show only records of this type (four character record code). May " "be specified multiple times. Only affects dump mode.") @@ -262,7 +262,7 @@ void printRaw(ESM::ESMReader &esm) int load(Arguments& info) { ESM::ESMReader& esm = info.reader; - esm.setEncoding(info.encoding); + esm.setEncoding(ToUTF8::CalculateEncoding(info.encoding)); std::string filename = info.filename; std::cout << "Loading file: " << filename << std::endl; @@ -321,7 +321,7 @@ int load(Arguments& info) if (info.types.size() > 0) { std::vector::iterator match; - match = std::find(info.types.begin(), info.types.end(), + match = std::find(info.types.begin(), info.types.end(), n.toString()); if (match == info.types.end()) interested = false; } @@ -425,7 +425,7 @@ int clone(Arguments& info) if (++i % 3 == 0) std::cout << std::endl; } - + if (i % 3 != 0) std::cout << std::endl; @@ -450,7 +450,7 @@ int clone(Arguments& info) for (Records::iterator it = records.begin(); it != records.end() && i > 0; ++it) { EsmTool::RecordBase *record = *it; - + name.val = record->getType().val; esm.startRecord(name.toString(), record->getFlags()); @@ -485,7 +485,7 @@ int clone(Arguments& info) std::cerr << "\r" << perc << "%"; } } - + std::cout << "\rDone!" << std::endl; esm.close(); @@ -513,7 +513,7 @@ int comp(Arguments& info) fileOne.encoding = info.encoding; fileTwo.encoding = info.encoding; - + fileOne.filename = info.filename; fileTwo.filename = info.outname; @@ -534,9 +534,9 @@ int comp(Arguments& info) std::cout << "Not equal, different amount of records." << std::endl; return 1; } - - - + + + return 0; } diff --git a/apps/launcher/model/datafilesmodel.cpp b/apps/launcher/model/datafilesmodel.cpp index d85a15e73..6d70c6031 100644 --- a/apps/launcher/model/datafilesmodel.cpp +++ b/apps/launcher/model/datafilesmodel.cpp @@ -272,7 +272,7 @@ void DataFilesModel::addMasters(const QString &path) foreach (const QString &path, dir.entryList()) { try { ESM::ESMReader fileReader; - fileReader.setEncoding(mEncoding.toStdString()); + fileReader.setEncoding(ToUTF8::CalculateEncoding(mEncoding.toStdString())); fileReader.open(dir.absoluteFilePath(path).toStdString()); ESM::ESMReader::MasterList mlist = fileReader.getMasters(); @@ -335,7 +335,7 @@ void DataFilesModel::addPlugins(const QString &path) try { ESM::ESMReader fileReader; - fileReader.setEncoding(mEncoding.toStdString()); + fileReader.setEncoding(ToUTF8::CalculateEncoding(mEncoding.toStdString())); fileReader.open(dir.absoluteFilePath(path).toStdString()); ESM::ESMReader::MasterList mlist = fileReader.getMasters(); diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2299053cd..9c31124b4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -334,12 +335,16 @@ void OMW::Engine::go() mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); + //Load translation data + std::unique_ptr translationDataStorage(new TranslationData::Storage(mEncoding)); + translationDataStorage->loadTranslationData(mFileCollections, mMaster); + // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); mEnvironment.setWindowManager (new MWGui::WindowManager( mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), - mCfgMgr.getCachePath ().string(), mScriptConsoleMode)); + mCfgMgr.getCachePath ().string(), mScriptConsoleMode, translationDataStorage.release())); // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); @@ -487,7 +492,7 @@ void OMW::Engine::showFPS(int level) mFpsLevel = level; } -void OMW::Engine::setEncoding(const std::string& encoding) +void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 57402c91e..2d2d58234 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -59,7 +59,7 @@ namespace OMW class Engine : private Ogre::FrameListener { MWBase::Environment mEnvironment; - std::string mEncoding; + ToUTF8::FromType mEncoding; Files::PathContainer mDataDirs; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; @@ -154,7 +154,7 @@ namespace OMW void setCompileAll (bool all); /// Font encoding - void setEncoding(const std::string& encoding); + void setEncoding(const ToUTF8::FromType& encoding); void setAnimationVerbose(bool animverbose); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 0563fdbbb..8b5c5c6d6 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -181,21 +181,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // Font encoding settings std::string encoding(variables["encoding"].as()); - if (encoding == "win1250") - { - std::cout << "Using Central and Eastern European font encoding." << std::endl; - engine.setEncoding(encoding); - } - else if (encoding == "win1251") - { - std::cout << "Using Cyrillic font encoding." << std::endl; - engine.setEncoding(encoding); - } - else - { - std::cout << "Using default (English) font encoding." << std::endl; - engine.setEncoding("win1252"); - } + std::cout << ToUTF8::EncodingUsingMessage(encoding) << std::endl; + engine.setEncoding(ToUTF8::CalculateEncoding(encoding)); // directory settings engine.enableFSStrict(variables["fs-strict"].as()); diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 843d1af4c..09a15a2cb 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -204,33 +204,10 @@ namespace MWClass std::string text; - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - if (ref->mRef.mTeleport) { - std::string dest; - if (ref->mRef.mDestCell != "") - { - // door leads to an interior, use interior name as tooltip - dest = ref->mRef.mDestCell; - } - else - { - // door leads to exterior, use cell name (if any), otherwise translated region name - int x,y; - MWBase::Environment::get().getWorld()->positionToIndex (ref->mRef.mDoorDest.pos[0], ref->mRef.mDoorDest.pos[1], x, y); - const ESM::Cell* cell = store.get().find(x,y); - if (cell->mName != "") - dest = cell->mName; - else - { - const ESM::Region* region = - store.get().find(cell->mRegion); - dest = region->mName; - } - } text += "\n#{sTo}"; - text += "\n"+dest; + text += "\n" + getDestination(*ref); } if (ref->mRef.mLockLevel > 0) @@ -246,6 +223,37 @@ namespace MWClass return info; } + std::string Door::getDestination (const MWWorld::LiveCellRef& door) + { + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + std::string dest; + if (door.mRef.mDestCell != "") + { + // door leads to an interior, use interior name as tooltip + dest = door.mRef.mDestCell; + } + else + { + // door leads to exterior, use cell name (if any), otherwise translated region name + int x,y; + MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.mDoorDest.pos[0], door.mRef.mDoorDest.pos[1], x, y); + const ESM::Cell* cell = store.get().find(x,y); + if (cell->mName != "") + dest = cell->mName; + else + { + const ESM::Region* region = + store.get().find(cell->mRegion); + + //name as is, not a token + return region->mName; + } + } + + return "#{sCell=" + dest + "}"; + } + MWWorld::Ptr Door::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index b0f86f12d..05ba0248b 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -31,6 +31,9 @@ namespace MWClass virtual MWGui::ToolTipInfo getToolTipInfo (const MWWorld::Ptr& ptr) const; ///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip. + static std::string getDestination (const MWWorld::LiveCellRef& door); + ///< @return destination cell name or token + virtual void lock (const MWWorld::Ptr& ptr, int lockLevel) const; ///< Lock object diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 9b4075f57..689baf488 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -319,7 +319,7 @@ void HUD::setCellName(const std::string& cellName) mCellNameTimer = 5.0f; mCellName = cellName; - mCellNameBox->setCaption(mCellName); + mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}"); mCellNameBox->setVisible(mMapVisible); } } diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 0a26ebb8f..4e2ee517e 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -299,7 +299,7 @@ MapWindow::~MapWindow() void MapWindow::setCellName(const std::string& cellName) { - setTitle(cellName); + setTitle("#{sCell=" + cellName + "}"); } void MapWindow::addVisitedLocation(const std::string& name, int x, int y) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 376eca88d..fbe1250e3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -55,7 +55,8 @@ using namespace MWGui; WindowManager::WindowManager( const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, - const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts) + const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + TranslationData::Storage* pTranslationDataStorage) : mGuiManager(NULL) , mHud(NULL) , mMap(NULL) @@ -104,6 +105,7 @@ WindowManager::WindowManager( , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHudEnabled(true) + , mTranslationDataStorage(pTranslationDataStorage) { // Set up the GUI system @@ -612,7 +614,7 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) if (cell->mCell->mName != "") { name = cell->mCell->mName; - mMap->addVisitedLocation (name, cell->mCell->getGridX (), cell->mCell->getGridY ()); + mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); } else { @@ -722,13 +724,25 @@ void WindowManager::setDragDrop(bool dragDrop) void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) { - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().find(_tag); + std::string tag(_tag); - if (setting && setting->mType == ESM::VT_String) - _result = setting->getString(); + std::string tokenToFind = "sCell="; + size_t tokenLength = tokenToFind.length(); + + if (tag.substr(0, tokenLength) == tokenToFind) + { + _result = mTranslationDataStorage->translateCellName(tag.substr(tokenLength)); + } else - _result = _tag; + { + const ESM::GameSetting *setting = + MWBase::Environment::get().getWorld()->getStore().get().find(tag); + + if (setting && setting->mType == ESM::VT_String) + _result = setting->getString(); + else + _result = tag; + } } void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 2e684b5da..40bff0eb0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -14,6 +14,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" @@ -76,7 +77,8 @@ namespace MWGui WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, - const std::string& cacheDir, bool consoleOnlyScripts); + const std::string& cacheDir, bool consoleOnlyScripts, + TranslationData::Storage* pTranslationDataStorage); virtual ~WindowManager(); /** @@ -250,6 +252,7 @@ namespace MWGui SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; + std::unique_ptr mTranslationDataStorage; CharacterCreation* mCharGen; diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 9917254ee..e14219aae 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -6,7 +6,7 @@ #include #include "store.hpp" -namespace MWWorld +namespace MWWorld { class ESMStore { @@ -158,7 +158,7 @@ namespace MWWorld std::ostringstream id; id << "$dynamic" << mDynamicCount++; record.mId = id.str(); - + T *ptr = store.insert(record); for (iterator it = mStores.begin(); it != mStores.end(); ++it) { if (it->second == &store) { @@ -179,7 +179,7 @@ namespace MWWorld template <> inline const ESM::NPC *ESMStore::insert(const ESM::NPC &npc) { - if (StringUtils::ciEqual(npc.mId, "player")) { + if (Misc::StringUtils::ciEqual(npc.mId, "player")) { return mNpcs.insert(npc); } else if (mNpcs.search(npc.mId) != 0) { std::ostringstream msg; @@ -191,7 +191,7 @@ namespace MWWorld std::ostringstream id; id << "$dynamic" << mDynamicCount++; record.mId = id.str(); - + ESM::NPC *ptr = mNpcs.insert(record); mIds[ptr->mId] = ESM::REC_NPC_; return ptr; diff --git a/apps/openmw/mwworld/recordcmp.hpp b/apps/openmw/mwworld/recordcmp.hpp index 0b1655100..7de4f5565 100644 --- a/apps/openmw/mwworld/recordcmp.hpp +++ b/apps/openmw/mwworld/recordcmp.hpp @@ -1,62 +1,12 @@ #ifndef OPENMW_MWWORLD_RECORDCMP_H #define OPENMW_MWWORLD_RECORDCMP_H -#include #include -#include #include namespace MWWorld { - /// \todo move this to another location - class StringUtils - { - struct ci - { - bool operator()(int x, int y) const { - return std::tolower(x) < std::tolower(y); - } - }; - - public: - static bool ciLess(const std::string &x, const std::string &y) { - return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); - } - - static bool ciEqual(const std::string &x, const std::string &y) { - if (x.size() != y.size()) { - return false; - } - std::string::const_iterator xit = x.begin(); - std::string::const_iterator yit = y.begin(); - for (; xit != x.end(); ++xit, ++yit) { - if (std::tolower(*xit) != std::tolower(*yit)) { - return false; - } - } - return true; - } - - /// Transforms input string to lower case w/o copy - static std::string &toLower(std::string &inout) { - std::transform( - inout.begin(), - inout.end(), - inout.begin(), - (int (*)(int)) std::tolower - ); - return inout; - } - - /// Returns lower case copy of input string - static std::string lowerCase(const std::string &in) - { - std::string out = in; - return toLower(out); - } - }; - struct RecordCmp { template @@ -67,17 +17,17 @@ namespace MWWorld template <> inline bool RecordCmp::operator()(const ESM::Dialogue &x, const ESM::Dialogue &y) const { - return StringUtils::ciLess(x.mId, y.mId); + return Misc::StringUtils::ciLess(x.mId, y.mId); } template <> inline bool RecordCmp::operator()(const ESM::Cell &x, const ESM::Cell &y) const { - return StringUtils::ciLess(x.mName, y.mName); + return Misc::StringUtils::ciLess(x.mName, y.mName); } template <> inline bool RecordCmp::operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { - return StringUtils::ciLess(x.mCell, y.mCell); + return Misc::StringUtils::ciLess(x.mCell, y.mCell); } } // end namespace diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 046de8c63..431cd3cf9 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -105,12 +105,12 @@ namespace MWWorld const T *search(const std::string &id) const { T item; - item.mId = StringUtils::lowerCase(id); + item.mId = Misc::StringUtils::lowerCase(id); typename std::vector::const_iterator it = std::lower_bound(mStatic.begin(), mStatic.end(), item, RecordCmp()); - if (it != mStatic.end() && StringUtils::ciEqual(it->mId, id)) { + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->mId, id)) { return &(*it); } @@ -134,7 +134,7 @@ namespace MWWorld void load(ESM::ESMReader &esm, const std::string &id) { mStatic.push_back(T()); - mStatic.back().mId = StringUtils::lowerCase(id); + mStatic.back().mId = Misc::StringUtils::lowerCase(id); mStatic.back().load(esm); } @@ -169,7 +169,7 @@ namespace MWWorld } T *insert(const T &item) { - std::string id = StringUtils::lowerCase(item.mId); + std::string id = Misc::StringUtils::lowerCase(item.mId); std::pair result = mDynamic.insert(std::pair(id, item)); T *ptr = &result.first->second; @@ -182,7 +182,7 @@ namespace MWWorld } bool erase(const std::string &id) { - std::string key = StringUtils::lowerCase(id); + std::string key = Misc::StringUtils::lowerCase(id); typename Dynamic::iterator it = mDynamic.find(key); if (it == mDynamic.end()) { return false; @@ -213,7 +213,7 @@ namespace MWWorld inline void Store::load(ESM::ESMReader &esm, const std::string &id) { mStatic.push_back(ESM::Script()); mStatic.back().load(esm); - StringUtils::toLower(mStatic.back().mId); + Misc::StringUtils::toLower(mStatic.back().mId); } template <> @@ -385,12 +385,12 @@ namespace MWWorld const ESM::Cell *search(const std::string &id) const { ESM::Cell cell; - cell.mName = StringUtils::lowerCase(id); + cell.mName = Misc::StringUtils::lowerCase(id); std::vector::const_iterator it = std::lower_bound(mInt.begin(), mInt.end(), cell, RecordCmp()); - if (it != mInt.end() && StringUtils::ciEqual(it->mName, id)) { + if (it != mInt.end() && Misc::StringUtils::ciEqual(it->mName, id)) { return &(*it); } @@ -490,7 +490,7 @@ namespace MWWorld const ESM::Cell *searchExtByName(const std::string &id) const { std::vector::const_iterator it = mSharedExt.begin(); for (; it != mSharedExt.end(); ++it) { - if (StringUtils::ciEqual((*it)->mName, id)) { + if (Misc::StringUtils::ciEqual((*it)->mName, id)) { return *it; } } @@ -501,7 +501,7 @@ namespace MWWorld const ESM::Cell *searchExtByRegion(const std::string &id) const { std::vector::const_iterator it = mSharedExt.begin(); for (; it != mSharedExt.end(); ++it) { - if (StringUtils::ciEqual((*it)->mRegion, id)) { + if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { return *it; } } @@ -541,7 +541,7 @@ namespace MWWorld ptr = &result.first->second; mSharedExt.push_back(ptr); } else { - std::string key = StringUtils::lowerCase(cell.mName); + std::string key = Misc::StringUtils::lowerCase(cell.mName); // duplicate insertions are avoided by search(ESM::Cell &) std::pair result = @@ -561,7 +561,7 @@ namespace MWWorld } bool erase(const std::string &id) { - std::string key = StringUtils::lowerCase(id); + std::string key = Misc::StringUtils::lowerCase(id); DynamicInt::iterator it = mDynamicInt.find(key); if (it == mDynamicInt.end()) { @@ -691,7 +691,7 @@ namespace MWWorld pg.mCell = name; iterator it = std::lower_bound(mIntBegin, mIntEnd, pg, RecordCmp()); - if (it != mIntEnd && StringUtils::ciEqual(it->mCell, name)) { + if (it != mIntEnd && Misc::StringUtils::ciEqual(it->mCell, name)) { return &(*it); } return 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f0b2efcec..97f9d0f11 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -11,6 +11,8 @@ #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" +#include "../mwclass/door.hpp" + #include "player.hpp" #include "manualref.hpp" #include "cellfunctors.hpp" @@ -168,7 +170,7 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - const std::string& encoding, std::map fallbackMap) + const ToUTF8::FromType& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), mNumFacing(0) @@ -237,7 +239,7 @@ namespace MWWorld MWWorld::Store::iterator it = regions.begin(); for (; it != regions.end(); ++it) { - if (MWWorld::StringUtils::ciEqual(cellName, it->mName)) + if (Misc::StringUtils::ciEqual(cellName, it->mName)) { return mStore.get().searchExtByRegion(it->mId); } @@ -805,7 +807,7 @@ namespace MWWorld { bool update = false; - if (StringUtils::ciEqual(record.mId, "player")) + if (Misc::StringUtils::ciEqual(record.mId, "player")) { static const char *sRaces[] = { @@ -816,7 +818,7 @@ namespace MWWorld int i=0; for (; sRaces[i]; ++i) - if (StringUtils::ciEqual (sRaces[i], record.mRace)) + if (Misc::StringUtils::ciEqual (sRaces[i], record.mRace)) break; mGlobalVariables->setInt ("pcrace", sRaces[i] ? i+1 : 0); @@ -825,9 +827,9 @@ namespace MWWorld mPlayer->getPlayer().get()->mBase; update = record.isMale() != player->isMale() || - !StringUtils::ciEqual(record.mRace, player->mRace) || - !StringUtils::ciEqual(record.mHead, player->mHead) || - !StringUtils::ciEqual(record.mHair, player->mHair); + !Misc::StringUtils::ciEqual(record.mRace, player->mRace) || + !Misc::StringUtils::ciEqual(record.mHead, player->mHead) || + !Misc::StringUtils::ciEqual(record.mHair, player->mHair); } const ESM::NPC *ret = mStore.insert(record); if (update) { @@ -1080,28 +1082,7 @@ namespace MWWorld if (ref.mRef.mTeleport) { World::DoorMarker newMarker; - - std::string dest; - if (ref.mRef.mDestCell != "") - { - // door leads to an interior, use interior name - dest = ref.mRef.mDestCell; - } - else - { - // door leads to exterior, use cell name (if any), otherwise translated region name - int x,y; - positionToIndex (ref.mRef.mDoorDest.pos[0], ref.mRef.mDoorDest.pos[1], x, y); - const ESM::Cell* cell = mStore.get().find(x,y); - if (cell->mName != "") - dest = cell->mName; - else - { - dest = mStore.get().find(cell->mRegion)->mName; - } - } - - newMarker.name = dest; + newMarker.name = MWClass::Door::getDestination(ref); ESM::Position pos = ref.mData.getPosition (); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0962c292c..a7634a57c 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -95,7 +95,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - const std::string& encoding, std::map fallbackMap); + const ToUTF8::FromType& encoding, std::map fallbackMap); virtual ~World(); @@ -228,7 +228,7 @@ namespace MWWorld virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); - ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. + ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; @@ -323,7 +323,7 @@ namespace MWWorld } virtual void renderPlayer(); - + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); virtual int canRest(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 29d6f46cd..2d2e21633 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -62,6 +62,10 @@ add_component_dir (interpreter miscopcodes opcodes runtime scriptopcodes spatialopcodes types ) +add_component_dir (translation_data + translation_data + ) + include_directories(${BULLET_INCLUDE_DIRS}) add_library(components STATIC ${COMPONENT_FILES}) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 2915a1ce7..580e006df 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -347,21 +347,9 @@ void ESMReader::fail(const std::string &msg) throw std::runtime_error(ss.str()); } -void ESMReader::setEncoding(const std::string& encoding) +void ESMReader::setEncoding(const ToUTF8::FromType& encoding) { - if (encoding == "win1250") - { - mEncoding = ToUTF8::WINDOWS_1250; - } - else if (encoding == "win1251") - { - mEncoding = ToUTF8::WINDOWS_1251; - } - else - { - // Default Latin encoding - mEncoding = ToUTF8::WINDOWS_1252; - } + mEncoding = encoding; } } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 6a74c53e8..1d0f6f580 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -234,7 +234,7 @@ public: void fail(const std::string &msg); /// Sets font encoding for ESM strings - void setEncoding(const std::string& encoding); + void setEncoding(const ToUTF8::FromType& encoding); private: Ogre::DataStreamPtr mEsm; diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index a32104bf3..112d66bb8 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,8 +1,58 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H +#include +#include + namespace Misc { +class StringUtils +{ + struct ci + { + bool operator()(int x, int y) const { + return std::tolower(x) < std::tolower(y); + } + }; + +public: + static bool ciLess(const std::string &x, const std::string &y) { + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); + } + + static bool ciEqual(const std::string &x, const std::string &y) { + if (x.size() != y.size()) { + return false; + } + std::string::const_iterator xit = x.begin(); + std::string::const_iterator yit = y.begin(); + for (; xit != x.end(); ++xit, ++yit) { + if (std::tolower(*xit) != std::tolower(*yit)) { + return false; + } + } + return true; + } + + /// Transforms input string to lower case w/o copy + static std::string &toLower(std::string &inout) { + std::transform( + inout.begin(), + inout.end(), + inout.begin(), + (int (*)(int)) std::tolower + ); + return inout; + } + + /// Returns lower case copy of input string + static std::string lowerCase(const std::string &in) + { + std::string out = in; + return toLower(out); + } +}; + /// Returns true if str1 begins with substring str2 bool begins(const char* str1, const char* str2); diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 6f0ed8bfd..ee1e56229 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -357,3 +357,23 @@ std::string ToUTF8::getLegacyEnc(ToUTF8::FromType to) // Return a string return std::string(&output[0], outlen); } + +ToUTF8::FromType ToUTF8::CalculateEncoding(const std::string& encodingName) +{ + if (encodingName == "win1250") + return ToUTF8::WINDOWS_1250; + else if (encodingName == "win1251") + return ToUTF8::WINDOWS_1251; + else + return ToUTF8::WINDOWS_1252; +} + +std::string ToUTF8::EncodingUsingMessage(const std::string& encodingName) +{ + if (encodingName == "win1250") + return "Using Central and Eastern European font encoding."; + else if (encodingName == "win1251") + return "Using Cyrillic font encoding."; + else + return "Using default (English) font encoding."; +} diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index 69e9fc92c..9982213c9 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -22,6 +22,9 @@ namespace ToUTF8 // page. std::string getUtf8(FromType from); std::string getLegacyEnc(FromType to); + + FromType CalculateEncoding(const std::string& encodingName); + std::string EncodingUsingMessage(const std::string& encodingName); } #endif diff --git a/components/translation_data/translation_data.cpp b/components/translation_data/translation_data.cpp new file mode 100644 index 000000000..cd124bfbc --- /dev/null +++ b/components/translation_data/translation_data.cpp @@ -0,0 +1,104 @@ +#include "translation_data.hpp" +#include + +#include + +namespace TranslationData +{ + void Storage::loadTranslationData(const Files::Collections& dataFileCollections, + const std::string& esmFileName) + { + std::string esmNameNoExtension(Misc::StringUtils::lowerCase(esmFileName)); + //changing the extension + size_t dotPos = esmNameNoExtension.rfind('.'); + if (dotPos != std::string::npos) + esmNameNoExtension.resize(dotPos); + + loadData(mCellNamesTranslations, esmNameNoExtension, ".cel", dataFileCollections); + loadData(mPhraseForms, esmNameNoExtension, ".top", dataFileCollections); + loadData(mTopicIDs, esmNameNoExtension, ".mrk", dataFileCollections); + } + + void Storage::loadData(ContainerType& container, + const std::string& fileNameNoExtension, + const std::string& extension, + const Files::Collections& dataFileCollections) + { + std::string path; + try + { + path = dataFileCollections.getCollection(extension).getPath(fileNameNoExtension + extension).string(); + } + catch(...) + { + //no file + return; + } + + std::ifstream stream(path); + if (stream.is_open()) + { + loadDataFromStream(container, stream); + stream.close(); + } + } + + void Storage::loadDataFromStream(ContainerType& container, std::istream& stream) + { + std::string line; + while (!stream.eof()) + { + std::getline( stream, line ); + if (!line.empty() && *line.rbegin() == '\r') + line.resize(line.size() - 1); + + if (!line.empty()) + { + char* buffer = ToUTF8::getBuffer(line.size() + 1); + //buffer has at least line.size() + 1 bytes, so it must be safe + strcpy(buffer, line.c_str()); + line = ToUTF8::getUtf8(mEncoding); + + size_t tab_pos = line.find('\t'); + if (tab_pos != std::string::npos && tab_pos > 0 && tab_pos < line.size() - 1) + { + std::string key = line.substr(0, tab_pos); + std::string value = line.substr(tab_pos + 1); + + if (!key.empty() && !value.empty()) + container.insert(std::make_pair(key, value)); + } + } + } + } + + std::string Storage::translateCellName(const std::string& cellName) const + { + auto entry = mCellNamesTranslations.find(cellName); + + if (entry == mCellNamesTranslations.end()) + return cellName; + + return entry->second; + } + + std::string Storage::topicID(const std::string& phrase) const + { + std::string result; + + //seeking for the standard phrase form + auto phraseFormsIterator = mPhraseForms.find(phrase); + if (phraseFormsIterator != mPhraseForms.end()) + result = phraseFormsIterator->second; + else + result = phrase; + + + //seeking for the topic ID + auto topicIDIterator = mTopicIDs.find(result); + if (topicIDIterator != mTopicIDs.end()) + result = topicIDIterator->second; + + return result; + } +} diff --git a/components/translation_data/translation_data.hpp b/components/translation_data/translation_data.hpp new file mode 100644 index 000000000..7f4162c09 --- /dev/null +++ b/components/translation_data/translation_data.hpp @@ -0,0 +1,36 @@ +#ifndef COMPONENTS_TRANSLATION_DATA_H +#define COMPONENTS_TRANSLATION_DATA_H + +#include +#include + +namespace TranslationData +{ + class Storage + { + public: + Storage(const ToUTF8::FromType& encoding) : mEncoding(encoding) {} + + void loadTranslationData(const Files::Collections& dataFileCollections, + const std::string& esmFileName); + + std::string translateCellName(const std::string& cellName) const; + std::string topicID(const std::string& phrase) const; + + private: + typedef std::map ContainerType; + + void loadData(ContainerType& container, + const std::string& fileNameNoExtension, + const std::string& extension, + const Files::Collections& dataFileCollections); + + void loadDataFromStream(ContainerType& container, std::istream& stream); + + + ToUTF8::FromType mEncoding; + std::map mCellNamesTranslations, mTopicIDs, mPhraseForms; + }; +} + +#endif From 1f71395660d75ef5eedfb8c2eeac028345aaafb8 Mon Sep 17 00:00:00 2001 From: lazydev Date: Tue, 25 Dec 2012 23:20:39 +0400 Subject: [PATCH 182/916] renaming of translation component; removing of C++11 features --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++-- components/CMakeLists.txt | 4 ++-- .../translation.cpp} | 13 +++++++++---- .../translation.hpp} | 0 5 files changed, 15 insertions(+), 10 deletions(-) rename components/{translation_data/translation_data.cpp => translation/translation.cpp} (89%) rename components/{translation_data/translation_data.hpp => translation/translation.hpp} (100%) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9c31124b4..3a7b6f6cf 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include @@ -336,7 +336,7 @@ void OMW::Engine::go() mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); //Load translation data - std::unique_ptr translationDataStorage(new TranslationData::Storage(mEncoding)); + std::auto_ptr translationDataStorage(new TranslationData::Storage(mEncoding)); translationDataStorage->loadTranslationData(mFileCollections, mMaster); // Create window manager - this manages all the MW-specific GUI windows diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 40bff0eb0..ad3c9b736 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -14,7 +14,7 @@ #include #include -#include +#include #include "../mwbase/windowmanager.hpp" @@ -252,7 +252,7 @@ namespace MWGui SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; - std::unique_ptr mTranslationDataStorage; + std::auto_ptr mTranslationDataStorage; CharacterCreation* mCharGen; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 2d2e21633..140bef771 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -62,8 +62,8 @@ add_component_dir (interpreter miscopcodes opcodes runtime scriptopcodes spatialopcodes types ) -add_component_dir (translation_data - translation_data +add_component_dir (translation + translation ) include_directories(${BULLET_INCLUDE_DIRS}) diff --git a/components/translation_data/translation_data.cpp b/components/translation/translation.cpp similarity index 89% rename from components/translation_data/translation_data.cpp rename to components/translation/translation.cpp index cd124bfbc..a178a053c 100644 --- a/components/translation_data/translation_data.cpp +++ b/components/translation/translation.cpp @@ -1,4 +1,4 @@ -#include "translation_data.hpp" +#include "translation.hpp" #include #include @@ -74,7 +74,8 @@ namespace TranslationData std::string Storage::translateCellName(const std::string& cellName) const { - auto entry = mCellNamesTranslations.find(cellName); + std::map::const_iterator entry = + mCellNamesTranslations.find(cellName); if (entry == mCellNamesTranslations.end()) return cellName; @@ -87,7 +88,9 @@ namespace TranslationData std::string result; //seeking for the standard phrase form - auto phraseFormsIterator = mPhraseForms.find(phrase); + std::map::const_iterator phraseFormsIterator = + mPhraseForms.find(phrase); + if (phraseFormsIterator != mPhraseForms.end()) result = phraseFormsIterator->second; else @@ -95,7 +98,9 @@ namespace TranslationData //seeking for the topic ID - auto topicIDIterator = mTopicIDs.find(result); + std::map::const_iterator topicIDIterator = + mTopicIDs.find(result); + if (topicIDIterator != mTopicIDs.end()) result = topicIDIterator->second; diff --git a/components/translation_data/translation_data.hpp b/components/translation/translation.hpp similarity index 100% rename from components/translation_data/translation_data.hpp rename to components/translation/translation.hpp From 049b0e66e0e63e5ac9c9ebdb837c371964ae856b Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Tue, 25 Dec 2012 20:27:30 +0100 Subject: [PATCH 183/916] - Restore ability to generate references in the same cell from multiple plugins - Disable some code related to deleting entries in the store so that it builds again --- apps/openmw/mwworld/cellstore.cpp | 2 -- apps/openmw/mwworld/esmstore.cpp | 2 ++ apps/openmw/mwworld/store.hpp | 48 +++++++++++++++---------------- components/esm/loadcell.cpp | 1 - 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ff8368dd1..ba8f5aa61 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -83,8 +83,6 @@ namespace MWWorld // Load references from all plugins that do something with this cell. for (size_t i = 0; i < mCell->mContextList.size(); i++) { - if (mCell->mContextList.size() > 1) - std::cout << "number of lists " << mCell->mContextList.size() << std::endl; // Reopen the ESM reader and seek to the right position. int index = mCell->mContextList.at(i).index; mCell->restore (esm[index], i); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 564126797..b1b9b1534 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -87,12 +87,14 @@ void ESMStore::load(ESM::ESMReader &esm) // ... unless it got deleted! This means that the following record // has been deleted, and trying to load it using standard assumptions // on the structure will (probably) fail. + /* if (esm.isNextSub("DELE")) { esm.skipRecord(); all.erase(id); it->second->remove(id); continue; } + */ it->second->load(esm, id); if (n.val==ESM::REC_DIAL) { diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index d4d632eff..fd3e9c59c 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -371,15 +371,15 @@ namespace MWWorld } }; - std::vector mInt; - std::vector mExt; + typedef std::map DynamicInt; + typedef std::map, ESM::Cell> DynamicExt; + + DynamicInt mInt; + DynamicExt mExt; std::vector mSharedInt; std::vector mSharedExt; - typedef std::map DynamicInt; - typedef std::map, ESM::Cell> DynamicExt; - DynamicInt mDynamicInt; DynamicExt mDynamicExt; @@ -401,11 +401,10 @@ namespace MWWorld ESM::Cell cell; cell.mName = StringUtils::lowerCase(id); - std::vector::const_iterator it = - std::lower_bound(mInt.begin(), mInt.end(), cell, RecordCmp()); + std::map::const_iterator it = mInt.find(cell.mName); - if (it != mInt.end() && StringUtils::ciEqual(it->mName, id)) { - return &(*it); + if (it != mInt.end() && StringUtils::ciEqual(it->second.mName, id)) { + return &(it->second); } DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); @@ -420,14 +419,12 @@ namespace MWWorld ESM::Cell cell; cell.mData.mX = x, cell.mData.mY = y; - std::vector::const_iterator it = - std::lower_bound(mExt.begin(), mExt.end(), cell, ExtCmp()); - - if (it != mExt.end() && it->mData.mX == x && it->mData.mY == y) { - return &(*it); + std::pair key(x, y); + std::map, ESM::Cell>::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); } - std::pair key(x, y); DynamicExt::const_iterator dit = mDynamicExt.find(key); if (dit != mDynamicExt.end()) { return &dit->second; @@ -457,18 +454,20 @@ namespace MWWorld } void setUp() { - typedef std::vector::iterator Iterator; + //typedef std::vector::iterator Iterator; + typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef std::map::iterator IntIterator; - std::sort(mInt.begin(), mInt.end(), RecordCmp()); + //std::sort(mInt.begin(), mInt.end(), RecordCmp()); mSharedInt.reserve(mInt.size()); - for (Iterator it = mInt.begin(); it != mInt.end(); ++it) { - mSharedInt.push_back(&(*it)); + for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { + mSharedInt.push_back(&(it->second)); } - std::sort(mExt.begin(), mExt.end(), ExtCmp()); + //std::sort(mExt.begin(), mExt.end(), ExtCmp()); mSharedExt.reserve(mExt.size()); - for (Iterator it = mExt.begin(); it != mExt.end(); ++it) { - mSharedExt.push_back(&(*it)); + for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { + mSharedExt.push_back(&(it->second)); } } @@ -497,14 +496,13 @@ namespace MWWorld // have new cell replace old cell *oldcell = *cell; } else - mInt.push_back(*cell); + mInt[cell->mName] = *cell; delete cell; } else { // Store exterior cells by grid position, try to merge with existing parent data. ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); - std::cout << "setup - " << oldcell << " " << cell->getGridX() << " " << cell->getGridY() << std::endl; if (oldcell) { // push the new references on the list of references to manage oldcell->mContextList.push_back(cell->mContextList.at(0)); @@ -513,7 +511,7 @@ namespace MWWorld // have new cell replace old cell *oldcell = *cell; } else - mExt.push_back(*cell); + mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; delete cell; } } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 0158af70a..b7f27b08d 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -201,7 +201,6 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mRefnum &= 0x00ffffff; // delete old plugin ID const ESM::ESMReader::MasterList &masters = esm.getMasters(); global = masters[local-1].index + 1; - std::cout << "moved ref: " << local << " " << global << std::endl; ref.mRefnum |= global << 24; // insert global plugin ID } else From 8ccec174811ccb3a58d1289531a0e29783f99602 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Wed, 26 Dec 2012 10:34:59 +0100 Subject: [PATCH 184/916] - Restore ability for plugins deleting records defined in parent files - Don't throw a runtime_error when trying to load a reference based on a deleted record (just a warning for now, should be closer to MW) --- apps/openmw/mwworld/cellstore.hpp | 11 +++--- apps/openmw/mwworld/esmstore.cpp | 15 ++++---- apps/openmw/mwworld/store.hpp | 58 ++++++++++++++++++++----------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index bf7581f6e..cf09496e8 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -61,13 +61,14 @@ namespace MWWorld { // for throwing exception on unhandled record type const MWWorld::Store &store = esmStore.get(); - const X *ptr = store.find(ref.mRefID); + const X *ptr = store.search(ref.mRefID); - /// \note redundant because Store::find() throws exception on miss + /// \note no longer redundant - changed to Store::search(), don't throw + /// an exception on miss, try to continue (that's how MW does it, anyway) if (ptr == NULL) { - throw std::runtime_error("Error resolving cell reference " + ref.mRefID); - } - mList[ref.mRefnum] = LiveRef(ref, ptr); + std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl; + } else + mList[ref.mRefnum] = LiveRef(ref, ptr); } LiveRef *find (const std::string& name) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index b1b9b1534..54050b38c 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -87,20 +87,18 @@ void ESMStore::load(ESM::ESMReader &esm) // ... unless it got deleted! This means that the following record // has been deleted, and trying to load it using standard assumptions // on the structure will (probably) fail. - /* if (esm.isNextSub("DELE")) { esm.skipRecord(); - all.erase(id); - it->second->remove(id); + it->second->eraseStatic(id); continue; } - */ it->second->load(esm, id); if (n.val==ESM::REC_DIAL) { // dirty hack, but it is better than non-const search() // or friends - dialogue = &mDialogs.mStatic.back(); + //dialogue = &mDialogs.mStatic.back(); + dialogue = const_cast(mDialogs.find(id)); assert (dialogue->mId == id); } else { dialogue = 0; @@ -140,12 +138,11 @@ void ESMStore::setUp() ESM::NPC item; item.mId = "player"; - std::vector::iterator pIt = - std::lower_bound(mNpcs.mStatic.begin(), mNpcs.mStatic.end(), item, RecordCmp()); - assert(pIt != mNpcs.mStatic.end() && pIt->mId == "player"); + const ESM::NPC *pIt = mNpcs.find("player"); + assert(pIt != NULL); mNpcs.insert(*pIt); - mNpcs.mStatic.erase(pIt); + mNpcs.eraseStatic(pIt->mId); } } // end namespace diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fd3e9c59c..77c9c7357 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -19,6 +19,8 @@ namespace MWWorld virtual int getSize() const = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; + + virtual bool eraseStatic(const std::string &id) {return false;} }; template @@ -85,7 +87,7 @@ namespace MWWorld template class Store : public StoreBase { - std::vector mStatic; + std::map mStatic; std::vector mShared; std::map mDynamic; @@ -107,11 +109,10 @@ namespace MWWorld T item; item.mId = StringUtils::lowerCase(id); - typename std::vector::const_iterator it = - std::lower_bound(mStatic.begin(), mStatic.end(), item, RecordCmp()); - - if (it != mStatic.end() && StringUtils::ciEqual(it->mId, id)) { - return &(*it); + typename std::map::const_iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && StringUtils::ciEqual(it->second.mId, id)) { + return &(it->second); } typename Dynamic::const_iterator dit = mDynamic.find(item.mId); @@ -133,18 +134,19 @@ namespace MWWorld } void load(ESM::ESMReader &esm, const std::string &id) { - mStatic.push_back(T()); - mStatic.back().mId = StringUtils::lowerCase(id); - mStatic.back().load(esm); + std::string idLower = StringUtils::lowerCase(id); + mStatic[idLower] = T(); + mStatic[idLower].mId = idLower; + mStatic[idLower].load(esm); } void setUp() { - std::sort(mStatic.begin(), mStatic.end(), RecordCmp()); + //std::sort(mStatic.begin(), mStatic.end(), RecordCmp()); mShared.reserve(mStatic.size()); - typename std::vector::iterator it = mStatic.begin(); + typename std::map::iterator it = mStatic.begin(); for (; it != mStatic.end(); ++it) { - mShared.push_back(&(*it)); + mShared.push_back(&(it->second)); } } @@ -181,6 +183,19 @@ namespace MWWorld return ptr; } + bool eraseStatic(const std::string &id) { + T item; + item.mId = StringUtils::lowerCase(id); + + typename std::map::const_iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && StringUtils::ciEqual(it->second.mId, id)) { + mStatic.erase(it); + } + + return true; + } + bool erase(const std::string &id) { std::string key = StringUtils::lowerCase(id); typename Dynamic::iterator it = mDynamic.find(key); @@ -204,16 +219,18 @@ namespace MWWorld template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - mStatic.push_back(ESM::Dialogue()); - mStatic.back().mId = id; - mStatic.back().load(esm); + std::string idLower = StringUtils::lowerCase(id); + mStatic[idLower] = ESM::Dialogue(); + mStatic[idLower].mId = id; // don't smash case here, as this line is printed... I think + mStatic[idLower].load(esm); } template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - mStatic.push_back(ESM::Script()); - mStatic.back().load(esm); - StringUtils::toLower(mStatic.back().mId); + ESM::Script scpt; + scpt.load(esm); + StringUtils::toLower(scpt.mId); + mStatic[scpt.mId] = scpt; } template <> @@ -478,6 +495,7 @@ namespace MWWorld // are not available until both cells have been loaded! So first, proceed as usual. // All cells have a name record, even nameless exterior cells. + std::string idLower = StringUtils::lowerCase(id); ESM::Cell *cell = new ESM::Cell; cell->mName = id; @@ -487,7 +505,7 @@ namespace MWWorld if(cell->mData.mFlags & ESM::Cell::Interior) { // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(id)); + ESM::Cell *oldcell = const_cast(search(idLower)); if (oldcell) { // push the new references on the list of references to manage oldcell->mContextList.push_back(cell->mContextList.at(0)); @@ -496,7 +514,7 @@ namespace MWWorld // have new cell replace old cell *oldcell = *cell; } else - mInt[cell->mName] = *cell; + mInt[idLower] = *cell; delete cell; } else From 2d468fec028d0ea3d324cdd2a5acab6da997edf6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 26 Dec 2012 16:19:59 +0100 Subject: [PATCH 185/916] made previous commits naming standard compliant --- apps/esmtool/esmtool.cpp | 2 +- apps/launcher/model/datafilesmodel.cpp | 4 ++-- apps/openmw/main.cpp | 4 ++-- components/to_utf8/to_utf8.cpp | 4 ++-- components/to_utf8/to_utf8.hpp | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 963656af5..0cd6e3905 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -262,7 +262,7 @@ void printRaw(ESM::ESMReader &esm) int load(Arguments& info) { ESM::ESMReader& esm = info.reader; - esm.setEncoding(ToUTF8::CalculateEncoding(info.encoding)); + esm.setEncoding(ToUTF8::calculateEncoding(info.encoding)); std::string filename = info.filename; std::cout << "Loading file: " << filename << std::endl; diff --git a/apps/launcher/model/datafilesmodel.cpp b/apps/launcher/model/datafilesmodel.cpp index 6d70c6031..716c9e902 100644 --- a/apps/launcher/model/datafilesmodel.cpp +++ b/apps/launcher/model/datafilesmodel.cpp @@ -272,7 +272,7 @@ void DataFilesModel::addMasters(const QString &path) foreach (const QString &path, dir.entryList()) { try { ESM::ESMReader fileReader; - fileReader.setEncoding(ToUTF8::CalculateEncoding(mEncoding.toStdString())); + fileReader.setEncoding(ToUTF8::calculateEncoding(mEncoding.toStdString())); fileReader.open(dir.absoluteFilePath(path).toStdString()); ESM::ESMReader::MasterList mlist = fileReader.getMasters(); @@ -335,7 +335,7 @@ void DataFilesModel::addPlugins(const QString &path) try { ESM::ESMReader fileReader; - fileReader.setEncoding(ToUTF8::CalculateEncoding(mEncoding.toStdString())); + fileReader.setEncoding(ToUTF8::calculateEncoding(mEncoding.toStdString())); fileReader.open(dir.absoluteFilePath(path).toStdString()); ESM::ESMReader::MasterList mlist = fileReader.getMasters(); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 8b5c5c6d6..96dbf8987 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -181,8 +181,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // Font encoding settings std::string encoding(variables["encoding"].as()); - std::cout << ToUTF8::EncodingUsingMessage(encoding) << std::endl; - engine.setEncoding(ToUTF8::CalculateEncoding(encoding)); + std::cout << ToUTF8::encodingUsingMessage(encoding) << std::endl; + engine.setEncoding(ToUTF8::calculateEncoding(encoding)); // directory settings engine.enableFSStrict(variables["fs-strict"].as()); diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index ee1e56229..7db611247 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -358,7 +358,7 @@ std::string ToUTF8::getLegacyEnc(ToUTF8::FromType to) return std::string(&output[0], outlen); } -ToUTF8::FromType ToUTF8::CalculateEncoding(const std::string& encodingName) +ToUTF8::FromType ToUTF8::calculateEncoding(const std::string& encodingName) { if (encodingName == "win1250") return ToUTF8::WINDOWS_1250; @@ -368,7 +368,7 @@ ToUTF8::FromType ToUTF8::CalculateEncoding(const std::string& encodingName) return ToUTF8::WINDOWS_1252; } -std::string ToUTF8::EncodingUsingMessage(const std::string& encodingName) +std::string ToUTF8::encodingUsingMessage(const std::string& encodingName) { if (encodingName == "win1250") return "Using Central and Eastern European font encoding."; diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index 9982213c9..f52ae73bd 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -23,8 +23,8 @@ namespace ToUTF8 std::string getUtf8(FromType from); std::string getLegacyEnc(FromType to); - FromType CalculateEncoding(const std::string& encodingName); - std::string EncodingUsingMessage(const std::string& encodingName); + FromType calculateEncoding(const std::string& encodingName); + std::string encodingUsingMessage(const std::string& encodingName); } #endif From 206c613b52e599b9366cbfa92278bf961e07bc8c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 26 Dec 2012 17:03:37 +0100 Subject: [PATCH 186/916] moved translation storage from GUI manager to engine --- apps/openmw/engine.cpp | 6 +++--- apps/openmw/engine.hpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.cpp | 6 +++--- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++-- components/translation/translation.cpp | 5 +++++ components/translation/translation.hpp | 3 ++- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3a7b6f6cf..b995300d5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -336,15 +336,14 @@ void OMW::Engine::go() mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); //Load translation data - std::auto_ptr translationDataStorage(new TranslationData::Storage(mEncoding)); - translationDataStorage->loadTranslationData(mFileCollections, mMaster); + mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); mEnvironment.setWindowManager (new MWGui::WindowManager( mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), - mCfgMgr.getCachePath ().string(), mScriptConsoleMode, translationDataStorage.release())); + mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage)); // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); @@ -495,6 +494,7 @@ void OMW::Engine::showFPS(int level) void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; + mTranslationDataStorage.setEncoding (encoding); } void OMW::Engine::setFallbackValues(std::map fallbackMap) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 2d2d58234..cbc627b83 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "mwbase/environment.hpp" @@ -79,9 +80,9 @@ namespace OMW Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; - Files::Collections mFileCollections; bool mFSStrict; + TranslationData::Storage mTranslationDataStorage; // not implemented Engine (const Engine&); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index fbe1250e3..cdcb615dc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -56,7 +56,7 @@ using namespace MWGui; WindowManager::WindowManager( const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - TranslationData::Storage* pTranslationDataStorage) + TranslationData::Storage& translationDataStorage) : mGuiManager(NULL) , mHud(NULL) , mMap(NULL) @@ -105,7 +105,7 @@ WindowManager::WindowManager( , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHudEnabled(true) - , mTranslationDataStorage(pTranslationDataStorage) + , mTranslationDataStorage (translationDataStorage) { // Set up the GUI system @@ -731,7 +731,7 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r if (tag.substr(0, tokenLength) == tokenToFind) { - _result = mTranslationDataStorage->translateCellName(tag.substr(tokenLength)); + _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); } else { diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ad3c9b736..b252254a0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -78,7 +78,7 @@ namespace MWGui WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - TranslationData::Storage* pTranslationDataStorage); + TranslationData::Storage& translationDataStorage); virtual ~WindowManager(); /** @@ -252,7 +252,7 @@ namespace MWGui SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; - std::auto_ptr mTranslationDataStorage; + TranslationData::Storage& mTranslationDataStorage; CharacterCreation* mCharGen; diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index a178a053c..e6c6a0233 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -106,4 +106,9 @@ namespace TranslationData return result; } + + void Storage::setEncoding (const ToUTF8::FromType& encoding) + { + mEncoding = encoding; + } } diff --git a/components/translation/translation.hpp b/components/translation/translation.hpp index 7f4162c09..0160bc48a 100644 --- a/components/translation/translation.hpp +++ b/components/translation/translation.hpp @@ -9,7 +9,6 @@ namespace TranslationData class Storage { public: - Storage(const ToUTF8::FromType& encoding) : mEncoding(encoding) {} void loadTranslationData(const Files::Collections& dataFileCollections, const std::string& esmFileName); @@ -17,6 +16,8 @@ namespace TranslationData std::string translateCellName(const std::string& cellName) const; std::string topicID(const std::string& phrase) const; + void setEncoding (const ToUTF8::FromType& encoding); + private: typedef std::map ContainerType; From afc2e840aeff2dc43a4020a2c333a22c4ef6d6fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 26 Dec 2012 17:06:33 +0100 Subject: [PATCH 187/916] renamed namespace TranslationData to Translation --- apps/openmw/engine.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 3 ++- apps/openmw/mwgui/windowmanagerimp.hpp | 10 +++++++--- components/translation/translation.cpp | 2 +- components/translation/translation.hpp | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index cbc627b83..00889197e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -82,7 +82,7 @@ namespace OMW Files::Collections mFileCollections; bool mFSStrict; - TranslationData::Storage mTranslationDataStorage; + Translation::Storage mTranslationDataStorage; // not implemented Engine (const Engine&); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cdcb615dc..caf6a4ab0 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -56,7 +57,7 @@ using namespace MWGui; WindowManager::WindowManager( const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - TranslationData::Storage& translationDataStorage) + Translation::Storage& translationDataStorage) : mGuiManager(NULL) , mHud(NULL) , mMap(NULL) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index b252254a0..aaa856aef 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -14,7 +14,6 @@ #include #include -#include #include "../mwbase/windowmanager.hpp" @@ -30,6 +29,11 @@ namespace Compiler class Extensions; } +namespace Translation +{ + class Storage; +} + namespace OEngine { namespace GUI @@ -78,7 +82,7 @@ namespace MWGui WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - TranslationData::Storage& translationDataStorage); + Translation::Storage& translationDataStorage); virtual ~WindowManager(); /** @@ -252,7 +256,7 @@ namespace MWGui SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; - TranslationData::Storage& mTranslationDataStorage; + Translation::Storage& mTranslationDataStorage; CharacterCreation* mCharGen; diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index e6c6a0233..feda76f6f 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -3,7 +3,7 @@ #include -namespace TranslationData +namespace Translation { void Storage::loadTranslationData(const Files::Collections& dataFileCollections, const std::string& esmFileName) diff --git a/components/translation/translation.hpp b/components/translation/translation.hpp index 0160bc48a..668d4c067 100644 --- a/components/translation/translation.hpp +++ b/components/translation/translation.hpp @@ -4,7 +4,7 @@ #include #include -namespace TranslationData +namespace Translation { class Storage { From e9ba7339f32fecbb974cb80ffd258a6bb8731620 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 26 Dec 2012 17:15:53 +0100 Subject: [PATCH 188/916] improved error handling --- components/files/multidircollection.cpp | 5 +++++ components/files/multidircollection.hpp | 3 +++ components/translation/translation.cpp | 22 +++++++++------------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index b44c42986..347de96a6 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -95,6 +95,11 @@ namespace Files return iter->second; } + bool MultiDirCollection::doesExist (const std::string& file) const + { + return mFiles.find (file)!=mFiles.end(); + } + MultiDirCollection::TIter MultiDirCollection::begin() const { return mFiles.begin(); diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp index e8abeb45d..3b420d677 100644 --- a/components/files/multidircollection.hpp +++ b/components/files/multidircollection.hpp @@ -73,6 +73,9 @@ namespace Files /// If the file does not exist, an exception is thrown. \a file must include /// the extension. + bool doesExist (const std::string& file) const; + ///< \return Does a file with the given name exist? + TIter begin() const; ///< Return iterator pointing to the first file. diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index feda76f6f..b559c6c1c 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -24,22 +24,18 @@ namespace Translation const std::string& extension, const Files::Collections& dataFileCollections) { - std::string path; - try - { - path = dataFileCollections.getCollection(extension).getPath(fileNameNoExtension + extension).string(); - } - catch(...) - { - //no file - return; - } + std::string fileName = fileNameNoExtension + extension; - std::ifstream stream(path); - if (stream.is_open()) + if (dataFileCollections.getCollection (extension).doesExist (fileName)) { + std::string path = dataFileCollections.getCollection (extension).getPath (fileName).string(); + + std::ifstream stream (path); + + if (!stream.is_open()) + throw std::runtime_error ("failed to open translation file: " + fileName); + loadDataFromStream(container, stream); - stream.close(); } } From a14b7e4a0fe80f07949b5fc7e019f4c5827b1baa Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 26 Dec 2012 18:07:56 +0000 Subject: [PATCH 189/916] small fixes on text defines --- apps/openmw/mwgui/formatting.cpp | 4 ++-- components/interpreter/defines.cpp | 22 +++++++++++++++------- components/interpreter/defines.hpp | 1 + 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 273034edd..4090b592d 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -74,7 +74,7 @@ std::vector BookTextParser::split(std::string text, const int width std::vector result; MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - text = Interpreter::fixDefinesDialog(text, interpreterContext); + text = Interpreter::fixDefinesBook(text, interpreterContext); boost::algorithm::replace_all(text, "
", "\n"); boost::algorithm::replace_all(text, "

", "\n\n"); @@ -176,7 +176,7 @@ std::vector BookTextParser::split(std::string text, const int width MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - text = Interpreter::fixDefinesDialog(text, interpreterContext); + text = Interpreter::fixDefinesBook(text, interpreterContext); mParent = parent; diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index bd355fd7c..29c78200d 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -1,6 +1,5 @@ #include "defines.hpp" -#include #include #include #include @@ -22,7 +21,7 @@ namespace Interpreter{ return a.length() > b.length(); } - std::string fixDefinesReal(std::string text, char eschar, Context& context){ + std::string fixDefinesReal(std::string text, char eschar, bool isBook, Context& context){ unsigned int start = 0; std::string retval = ""; @@ -107,7 +106,7 @@ namespace Interpreter{ retval += context.getCurrentCellName(); } - else if(eschar == '%'){ // In Dialogue, not messagebox + else if(eschar == '%' && !isBook) { // In Dialogue, not messagebox if( (found = Check(temp, "faction", &i, &start))){ retval += context.getNPCFaction(); } @@ -134,9 +133,9 @@ namespace Interpreter{ retval += context.getNPCName(); } } - else if(eschar == '^') { // In messagebox, not dialogue + else { // In messagebox or book, not dialogue - /* empty in messageboxes */ + /* empty outside dialogue */ if( (found = Check(temp, "faction", &i, &start))); else if((found = Check(temp, "nextpcrank", &i, &start))); else if((found = Check(temp, "pcnextrank", &i, &start))); @@ -164,6 +163,11 @@ namespace Interpreter{ } for(unsigned int j = 0; j < globals.size(); j++){ + if(globals[j].length() > temp.length()){ // Just in case there's a global with a huuuge name + std::string temp = text.substr(i+1, globals[j].length()); + transform(temp.begin(), temp.end(), temp.begin(), ::tolower); + } + if((found = Check(temp, globals[j], &i, &start))){ char type = context.getGlobalType(globals[j]); @@ -191,10 +195,14 @@ namespace Interpreter{ } std::string fixDefinesDialog(std::string text, Context& context){ - return fixDefinesReal(text, '%', context); + return fixDefinesReal(text, '%', false, context); } std::string fixDefinesMsgBox(std::string text, Context& context){ - return fixDefinesReal(text, '^', context); + return fixDefinesReal(text, '^', false, context); + } + + std::string fixDefinesBook(std::string text, Context& context){ + return fixDefinesReal(text, '%', true, context); } } diff --git a/components/interpreter/defines.hpp b/components/interpreter/defines.hpp index 4cfba21ea..00c4386b8 100644 --- a/components/interpreter/defines.hpp +++ b/components/interpreter/defines.hpp @@ -7,6 +7,7 @@ namespace Interpreter{ std::string fixDefinesDialog(std::string text, Context& context); std::string fixDefinesMsgBox(std::string text, Context& context); + std::string fixDefinesBook(std::string text, Context& context); } #endif From 716fbbbd74d3474fb0a36f8eff00fdd7da8152b5 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 26 Dec 2012 22:57:53 +0000 Subject: [PATCH 190/916] messageboxes during dialogue show up in dialogue window, and messageboxes are generated when an item is removed from inventory --- apps/openmw/mwgui/dialogue.cpp | 5 +++ apps/openmw/mwgui/dialogue.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 22 +++++++++----- apps/openmw/mwscript/containerextensions.cpp | 32 ++++++++++++++++++++ 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 258e9174c..e2b9f461a 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -370,6 +370,11 @@ void DialogueWindow::addText(std::string text) mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); } +void DialogueWindow::addMessageBox(std::string text) +{ + mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); +} + void DialogueWindow::addTitle(std::string text) { // This is called from the dialogue manager, so text is diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 082d92524..c4b86e6c8 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -65,6 +65,7 @@ namespace MWGui void setKeywords(std::list keyWord); void removeKeyword(std::string keyWord); void addText(std::string text); + void addMessageBox(std::string text); void addTitle(std::string text); void askQuestion(std::string question); void goodbye(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index caf6a4ab0..ebef71409 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -537,14 +537,20 @@ void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) void WindowManager::messageBox (const std::string& message, const std::vector& buttons) { - if (buttons.empty()) - { - mMessageBoxManager->createMessageBox(message); - } - else - { - mMessageBoxManager->createInteractiveMessageBox(message, buttons); - pushGuiMode(GM_InterMessageBox); + /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ + if(buttons.empty() && std::find(mGuiModes.begin(), mGuiModes.end(), GM_Dialogue) != mGuiModes.end()) + mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); + + else{ + if (buttons.empty()) + { + mMessageBoxManager->createMessageBox(message); + } + else + { + mMessageBoxManager->createInteractiveMessageBox(message, buttons); + pushGuiMode(GM_InterMessageBox); + } } } diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 7f4913b8a..07cf3b9e3 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -10,6 +10,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" @@ -106,12 +107,41 @@ namespace MWScript throw std::runtime_error ("second argument for RemoveItem must be non-negative"); MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); + + std::string itemName = ""; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; ++iter) { if (toLower(iter->getCellRef().mRefID) == toLower(item)) { + switch(iter.getType()){ + case MWWorld::ContainerStore::Type_Potion: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Apparatus: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Armor: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Book: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Clothing: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Ingredient: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Light: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Lockpick: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Miscellaneous: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Probe: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Repair: + itemName = iter->get()->mBase->mName; break; + case MWWorld::ContainerStore::Type_Weapon: + itemName = iter->get()->mBase->mName; break; + } + if (iter->getRefData().getCount()<=count) { count -= iter->getRefData().getCount(); @@ -124,6 +154,8 @@ namespace MWScript } } } + + MWBase::Environment::get().getWindowManager()->messageBox(itemName + " has been removed from your inventory.", std::vector()); // To be fully compatible with original Morrowind, we would need to check if // count is >= 0 here and throw an exception. But let's be tollerant instead. From 299a1f32ed59855c3be4305d1336799efaca3ec2 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 26 Dec 2012 23:52:16 +0000 Subject: [PATCH 191/916] cleanup --- apps/openmw/mwgui/windowmanagerimp.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index ebef71409..fe3cb7b11 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -537,20 +537,19 @@ void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) void WindowManager::messageBox (const std::string& message, const std::vector& buttons) { - /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ - if(buttons.empty() && std::find(mGuiModes.begin(), mGuiModes.end(), GM_Dialogue) != mGuiModes.end()) - mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); + if(buttons.empty()){ + /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ + if(std::find(mGuiModes.begin(), mGuiModes.end(), GM_Dialogue) != mGuiModes.end()) + mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); - else{ - if (buttons.empty()) - { - mMessageBoxManager->createMessageBox(message); - } else - { - mMessageBoxManager->createInteractiveMessageBox(message, buttons); - pushGuiMode(GM_InterMessageBox); - } + mMessageBoxManager->createMessageBox(message); + } + + else + { + mMessageBoxManager->createInteractiveMessageBox(message, buttons); + pushGuiMode(GM_InterMessageBox); } } From ba2301a1566e0655cbcb0d57d658ca7d3c145d39 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 27 Dec 2012 00:49:39 +0000 Subject: [PATCH 192/916] removed redundant code thanks to scrawl --- apps/openmw/mwscript/containerextensions.cpp | 27 +------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 07cf3b9e3..813ac555f 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -115,32 +115,7 @@ namespace MWScript { if (toLower(iter->getCellRef().mRefID) == toLower(item)) { - switch(iter.getType()){ - case MWWorld::ContainerStore::Type_Potion: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Apparatus: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Armor: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Book: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Clothing: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Ingredient: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Light: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Lockpick: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Miscellaneous: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Probe: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Repair: - itemName = iter->get()->mBase->mName; break; - case MWWorld::ContainerStore::Type_Weapon: - itemName = iter->get()->mBase->mName; break; - } + itemName = MWWorld::Class::get(*iter).getName(*iter); if (iter->getRefData().getCount()<=count) { From 2736e84e496220eb0f4e3381d190c1edba740e7f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 27 Dec 2012 11:04:53 +0100 Subject: [PATCH 193/916] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 063e9940a..84a596a6b 100644 --- a/credits.txt +++ b/credits.txt @@ -26,6 +26,7 @@ Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) Karl-Felix Glatzer (k1ll) +lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) Marcin Hulist (Gohan) From ad9b86058b503cc1f3b4ee5821e2bc02f0bde9b0 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 27 Dec 2012 15:28:13 +0000 Subject: [PATCH 194/916] replaced explicit text with GMST entries, thanks to zinnschlag --- apps/openmw/mwgui/dialogue.cpp | 2 +- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwscript/containerextensions.cpp | 27 ++++++++++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e2b9f461a..2809e842a 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -370,7 +370,7 @@ void DialogueWindow::addText(std::string text) mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); } -void DialogueWindow::addMessageBox(std::string text) +void DialogueWindow::addMessageBox(const std::string& text) { mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index c4b86e6c8..72bb6d19a 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -65,7 +65,7 @@ namespace MWGui void setKeywords(std::list keyWord); void removeKeyword(std::string keyWord); void addText(std::string text); - void addMessageBox(std::string text); + void addMessageBox(const std::string& text); void addTitle(std::string text); void askQuestion(std::string question); void goodbye(); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 813ac555f..2ac18a554 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -3,6 +3,10 @@ #include +#include + +#include + #include #include @@ -102,13 +106,14 @@ namespace MWScript Interpreter::Type_Integer count = runtime[0].mInteger; runtime.pop(); - + if (count<0) throw std::runtime_error ("second argument for RemoveItem must be non-negative"); MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); std::string itemName = ""; + Interpreter::Type_Integer originalCount = count; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; ++iter) @@ -129,8 +134,26 @@ namespace MWScript } } } + + /* The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory */ + std::string msgBox; + if(originalCount - count > 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); + std::stringstream temp; + temp << boost::format(msgBox) % (originalCount - count) % itemName; + msgBox = temp.str(); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); + std::stringstream temp; + temp << boost::format(msgBox) % itemName; + msgBox = temp.str(); + } - MWBase::Environment::get().getWindowManager()->messageBox(itemName + " has been removed from your inventory.", std::vector()); + if(originalCount - count > 0) + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); // To be fully compatible with original Morrowind, we would need to check if // count is >= 0 here and throw an exception. But let's be tollerant instead. From 2cef65a056d7d67ba5f6607efefeeb18bef43e24 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Thu, 27 Dec 2012 20:11:58 +0100 Subject: [PATCH 195/916] - Remove some files that are no longer in upstream/master --- components/esm_store/reclists.hpp | 735 ------------------------------ components/esm_store/store.cpp | 124 ----- 2 files changed, 859 deletions(-) delete mode 100644 components/esm_store/reclists.hpp delete mode 100644 components/esm_store/store.cpp diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp deleted file mode 100644 index 14452fca9..000000000 --- a/components/esm_store/reclists.hpp +++ /dev/null @@ -1,735 +0,0 @@ -#ifndef _GAME_ESM_RECLISTS_H -#define _GAME_ESM_RECLISTS_H - -#include "components/esm/records.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -using namespace boost::algorithm; - -namespace ESMS -{ - using namespace ESM; - - struct RecList - { - virtual ~RecList() {} - - virtual void load(ESMReader &esm, const std::string &id) = 0; - virtual int getSize() = 0; - virtual void remove(const std::string &id) {}; - virtual void listIdentifier (std::vector& identifier) const = 0; - - static std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } - }; - - typedef std::map RecListList; - - template - struct RecListT : RecList - { - virtual ~RecListT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = toLower (id); - list[id2].load(esm); - } - - // Delete the given object ID. Plugin files support this, so we need to do this, too. - void remove(const std::string &id) - { - std::string id2 = toLower (id); - - list.erase(id2); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - // Same as RecListT, but does not case-smash the IDs - // Note that lookups (search or find) are still case insensitive - template - struct RecListCaseT : RecList - { - virtual ~RecListCaseT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - //std::string id2 = toLower (id); - - list[id].load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - for (typename MapType::const_iterator iter = list.begin(); - iter != list.end(); ++iter) - { - if (toLower(iter->first) == id2) - return &iter->second; - } - - return NULL; - } - - // non-const version - X* search(const std::string &id) - { - std::string id2 = toLower (id); - - for (typename MapType::iterator iter = list.begin(); - iter != list.end(); ++iter) - { - if (toLower(iter->first) == id2) - return &iter->second; - } - - return NULL; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - /// Modified version of RecListT for records, that need to store their own ID - template - struct RecListWithIDT : RecList - { - virtual ~RecListWithIDT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = toLower (id); - list[id2].mId = id2; - list[id2].load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - // The only difference to the above is a slight change to the load() - // function. We might merge these together later, and store the id - // in all the structs. - template - struct RecIDListT : RecList - { - virtual ~RecIDListT() {} - - typedef std::map MapType; - - MapType list; - - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = toLower (id); - X& ref = list[id2]; - - ref.mId = id; - ref.load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - /* Land textures are indexed by an integer number - */ - struct LTexList : RecList - { - virtual ~LTexList() {} - - // For multiple ESM/ESP files we need one list per file. - typedef std::vector LandTextureList; - std::vector ltex; - - LTexList() - { - ltex.push_back(LandTextureList()); - LandTextureList <exl = ltex[0]; - // More than enough to hold Morrowind.esm. Extra lists for plugins will we - // added on-the-fly in a different method. - ltexl.reserve(128); - } - - const LandTexture* search(size_t index, size_t plugin) const - { - assert(plugin < ltex.size()); - const LandTextureList <exl = ltex[plugin]; - - assert(index < ltexl.size()); - return <exl.at(index); - } - - // "getSize" returns the number of individual terrain palettes. - // "getSizePlugin" returns the number of land textures in a specific palette. - int getSize() { return ltex.size(); } - int getSize() const { return ltex.size(); } - - int getSizePlugin(size_t plugin) { assert(plugin < ltex.size()); return ltex[plugin].size(); } - int getSizePlugin(size_t plugin) const { assert(plugin < ltex.size()); return ltex[plugin].size(); } - - virtual void listIdentifier (std::vector& identifier) const {} - - void load(ESMReader &esm, const std::string &id, size_t plugin) - { - LandTexture lt; - lt.load(esm); - lt.mId = id; - - // Make sure we have room for the structure - if (plugin >= ltex.size()) { - ltex.resize(plugin+1); - } - LandTextureList <exl = ltex[plugin]; - if(lt.mIndex + 1 > (int)ltexl.size()) - ltexl.resize(lt.mIndex+1); - - // Store it - ltexl[lt.mIndex] = lt; - } - - // Load all terrain palettes at the same size. Inherited virtual function - // from "RecList". Mostly useless, because we need the implementation - // above this one. - void load(ESMReader &esm, const std::string &id) - { - size_t plugin = esm.getIndex(); - load(esm, id, plugin); - } - }; - - /* Landscapes are indexed by the X,Y coordinates of the exterior - cell they belong to. - */ - struct LandList : RecList - { - virtual ~LandList() - { - for ( LandMap::iterator itr = lands.begin(); itr != lands.end(); ++itr ) - { - delete itr->second; - } - } - - // Map containing all landscapes - typedef std::pair LandCoord; - typedef std::map LandMap; - LandMap lands; - - int count; - LandList() : count(0) {} - int getSize() { return count; } - - virtual void listIdentifier (std::vector& identifier) const {} - - // Find land for the given coordinates. Return null if no mData. - Land *search(int x, int y) const - { - LandMap::const_iterator itr = lands.find(std::make_pair (x, y)); - if ( itr == lands.end() ) - { - return NULL; - } - - return itr->second; - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - - // Create the structure and load it. This actually skips the - // landscape data and remembers the file position for later. - Land *land = new Land(); - land->load(esm); - - // Store the structure - lands[std::make_pair (land->mX, land->mY)] = land; - } - }; - - struct ciLessBoost : std::binary_function -{ - bool operator() (const std::string & s1, const std::string & s2) const { - //case insensitive version of is_less - return lexicographical_compare(s1, s2, is_iless()); - } -}; - - - // Cells aren't simply indexed by name. Exterior cells are treated - // separately. - // TODO: case handling (cell names are case-insensitive, but they are also showen to the - // player, so we can't simply smash case. - struct CellList : RecList - { - // Total cell count. Used for statistics. - int count; - CellList() : count(0) {} - int getSize() { return count; } - - // List of interior cells. Indexed by cell name. - typedef std::map IntCells; - IntCells intCells; - - // List of exterior cells. Indexed as extCells[mX][mY]. - typedef std::map, ESM::Cell*> ExtCells; - ExtCells extCells; - - virtual void listIdentifier (std::vector& identifier) const - { - for (IntCells::const_iterator iter (intCells.begin()); iter!=intCells.end(); ++iter) - identifier.push_back (iter->first); - } - - virtual ~CellList() - { - for (IntCells::iterator it = intCells.begin(); it!=intCells.end(); ++it) - delete it->second; - - for (ExtCells::iterator it = extCells.begin(); it!=extCells.end(); ++it) - delete it->second; - } - - const ESM::Cell* searchInt(const std::string &id) const - { - IntCells::const_iterator iter = intCells.find(id); - - if (iter!=intCells.end()) - return iter->second; - - return 0; - } - - const ESM::Cell* findInt(const std::string &id) const - { - const ESM::Cell *cell = searchInt (id); - - if (!cell) - throw std::runtime_error ("Interior cell not found - " + id); - - return cell; - } - - const ESM::Cell *searchExt (int x, int y) const - { - ExtCells::const_iterator it = extCells.find (std::make_pair (x, y)); - - if (it==extCells.end()) - return 0; - - return it->second; - } - - const ESM::Cell *findExt (int x, int y) const - { - const ESM::Cell *cell = searchExt (x, y); - - if (!cell) - throw std::runtime_error ("Exterior cell not found"); - - return cell; - } - const ESM::Cell *searchExtByName (const std::string& id) const - { - for (ExtCells::const_iterator iter = extCells.begin(); iter!=extCells.end(); ++iter) - { - if (toLower (iter->second->mName) == toLower (id)) - return iter->second; - } - - return 0; - } - - const ESM::Cell *searchExtByRegion (const std::string& id) const - { - std::string id2 = toLower (id); - - for (ExtCells::const_iterator iter = extCells.begin(); iter!=extCells.end(); ++iter) - if (toLower (iter->second->mRegion)==id) - return iter->second; - - return 0; - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - - // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, - // and we merge all this data into one Cell object. However, we can't simply search for the cell id, - // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they - // are not available until both cells have been loaded! So first, proceed as usual. - - // All cells have a name record, even nameless exterior cells. - ESM::Cell *cell = new ESM::Cell; - cell->mName = id; - - // The cell itself takes care of all the hairy details - cell->load(esm); - - if(cell->mData.mFlags & ESM::Cell::Interior) - { - // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(searchInt(id)); - if (oldcell) { - cell->mContextList.push_back(oldcell->mContextList.at(0)); - delete oldcell; - } - intCells[id] = cell; - } - else - { - // Store exterior cells by grid position, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(searchExt(cell->getGridX(), cell->getGridY())); - if (oldcell) { - // The load order is important. Push the new source context on the *back* of the existing list, - // and then move the list to the new cell. - oldcell->mContextList.push_back(cell->mContextList.at(0)); - cell->mContextList = oldcell->mContextList; - delete oldcell; - } - extCells[std::make_pair (cell->mData.mX, cell->mData.mY)] = cell; - } - } - }; - - struct PathgridList : RecList - { - int count; - - // List of grids for interior cells. Indexed by cell name. - typedef std::map IntGrids; - IntGrids intGrids; - - // List of grids for exterior cells. Indexed as extCells[mX][mY]. - typedef std::map, ESM::Pathgrid*> ExtGrids; - ExtGrids extGrids; - - PathgridList() : count(0) {} - - virtual ~PathgridList() - { - for (IntGrids::iterator it = intGrids.begin(); it!=intGrids.end(); ++it) - delete it->second; - - for (ExtGrids::iterator it = extGrids.begin(); it!=extGrids.end(); ++it) - delete it->second; - } - - int getSize() { return count; } - - virtual void listIdentifier (std::vector& identifier) const - { - // do nothing - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - ESM::Pathgrid *grid = new ESM::Pathgrid; - grid->load(esm); - if (grid->mData.mX == 0 && grid->mData.mY == 0) - { - intGrids[grid->mCell] = grid; - } - else - { - extGrids[std::make_pair(grid->mData.mX, grid->mData.mY)] = grid; - } - } - - Pathgrid *find(int cellX, int cellY, const std::string &cellName) const - { - Pathgrid *result = search(cellX, cellY, cellName); - if (!result) - { - throw std::runtime_error("no pathgrid found for cell " + cellName); - } - return result; - } - - Pathgrid *search(int cellX, int cellY, const std::string &cellName) const - { - Pathgrid *result = NULL; - if (cellX == 0 && cellY == 0) // possibly interior - { - IntGrids::const_iterator it = intGrids.find(cellName); - if (it != intGrids.end()) - result = it->second; - } - else - { - ExtGrids::const_iterator it = extGrids.find(std::make_pair(cellX, cellY)); - if (it != extGrids.end()) - result = it->second; - } - return result; - } - - Pathgrid *search(const ESM::Cell &cell) const - { - int cellX, cellY; - if (cell.mData.mFlags & ESM::Cell::Interior) - { - cellX = cellY = 0; - } - else - { - cellX = cell.mData.mX; - cellY = cell.mData.mY; - } - return search(cellX, cellY, cell.mName); - } - }; - - template - struct ScriptListT : RecList - { - virtual ~ScriptListT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - X ref; - ref.load (esm); - - std::string realId = toLower (ref.mData.mName.toString()); - - std::swap (list[realId], ref); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - template - struct IndexListT - { - virtual ~IndexListT() {} - - typedef std::map MapType; - - MapType list; - - void load(ESMReader &esm) - { - X ref; - ref.load (esm); - int index = ref.mIndex; - list[index] = ref; - } - - int getSize() - { - return list.size(); - } - - virtual void listIdentifier (std::vector& identifier) const {} - - // Find the given object ID, or return NULL if not found. - const X* search (int id) const - { - typename MapType::const_iterator iter = list.find (id); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find (int id) const - { - const X *object = search (id); - - if (!object) - { - std::ostringstream error; - error << "object " << id << " not found"; - throw std::runtime_error (error.str()); - } - - return object; - } - }; - - /* We need special lists for: - - Path grids - */ -} -#endif diff --git a/components/esm_store/store.cpp b/components/esm_store/store.cpp deleted file mode 100644 index aeacfbacd..000000000 --- a/components/esm_store/store.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include "store.hpp" - -using namespace std; -using namespace ESM; -using namespace ESMS; - -/* -static string toStr(int i) -{ - char name[5]; - *((int*)name) = i; - name[4] = 0; - return std::string(name); -} -*/ - -void ESMStore::load(ESMReader &esm) -{ - set missing; - - ESM::Dialogue *dialogue = 0; - - // Loop through all records - while(esm.hasMoreRecs()) - { - NAME n = esm.getRecName(); - esm.getRecHeader(); - - // Look up the record type. - RecListList::iterator it = recLists.find(n.val); - - if(it == recLists.end()) - { - if (n.val==ESM::REC_INFO) - { - if (dialogue) - { - ESM::DialInfo info; - info.load (esm); - - dialogue->mInfo.push_back (info); - } - else - { - std::cerr << "error: info record without dialog" << std::endl; - esm.skipRecord(); - } - } - else if (n.val==ESM::REC_MGEF) - { - magicEffects.load (esm); - } - else if (n.val==ESM::REC_SKIL) - { - skills.load (esm); - } - else - { - // Not found (this would be an error later) - esm.skipRecord(); - missing.insert(n.toString()); - } - } - else - { - // Load it - std::string id = esm.getHNOString("NAME"); - // ... unless it got deleted! This means that the following record - // has been deleted, and trying to load it using standard assumptions - // on the structure will (probably) fail. - if (esm.isNextSub("DELE")) { - esm.skipRecord(); - all.erase(id); - it->second->remove(id); - continue; - } - it->second->load(esm, id); - - if (n.val==ESM::REC_DIAL) - { - RecListCaseT& recList = static_cast& > (*it->second); - - ESM::Dialogue* d = recList.search (id); - - assert (d != NULL); - - dialogue = d; - } - else - dialogue = 0; - - // Insert the reference into the global lookup - if(!id.empty() && - (n.val==REC_ACTI || n.val==REC_ALCH || n.val==REC_APPA || n.val==REC_ARMO || - n.val==REC_BOOK || n.val==REC_CLOT || n.val==REC_CONT || n.val==REC_CREA || - n.val==REC_DOOR || n.val==REC_INGR || n.val==REC_LEVC || n.val==REC_LEVI || - n.val==REC_LIGH || n.val==REC_LOCK || n.val==REC_MISC || n.val==REC_NPC_ || - n.val==REC_PROB || n.val==REC_REPA || n.val==REC_STAT || n.val==REC_WEAP) - ) - all[id] = n.val; - } - } - - for (int i = 0; i < Attribute::Length; ++i) - { - Attribute::AttributeID id = Attribute::sAttributeIds[i]; - attributes.list.insert(std::make_pair(id, Attribute(id, Attribute::sGmstAttributeIds[i], Attribute::sGmstAttributeDescIds[i]))); - } - - /* This information isn't needed on screen. But keep the code around - for debugging purposes later. - - cout << "\n" << recLists.size() << " record types:\n"; - for(RecListList::iterator it = recLists.begin(); it != recLists.end(); it++) - cout << " " << toStr(it->first) << ": " << it->second->getSize() << endl; - cout << "\nNot implemented yet: "; - for(set::iterator it = missing.begin(); - it != missing.end(); it++ ) - cout << *it << " "; - cout << endl; - */ -} From 8545667bbde8579e596ff1d302ab673504b4175b Mon Sep 17 00:00:00 2001 From: eduard Date: Fri, 28 Dec 2012 17:54:56 +0100 Subject: [PATCH 196/916] string compare and tolower --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 78 +++++++------------ apps/openmw/mwgui/inventorywindow.cpp | 15 +--- apps/openmw/mwscript/containerextensions.cpp | 17 +--- apps/openmw/mwworld/containerstore.cpp | 18 ++--- apps/openmw/mwworld/worldimp.cpp | 16 +--- components/esm_store/reclists.hpp | 41 ++++------ components/misc/stringops.cpp | 37 +++++++++ components/misc/stringops.hpp | 9 +++ 8 files changed, 101 insertions(+), 130 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 62f7df679..2c30ebf06 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -41,30 +41,6 @@ namespace { - std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } - - bool stringCompareNoCase (std::string first, std::string second) - { - unsigned int i=0; - while ( (itolower(second[i])) return false; - ++i; - } - if (first.length() bool selectCompare (char comp, T1 value1, T2 value2) @@ -72,7 +48,7 @@ namespace switch (comp) { case '0': return value1==value2; - case '1': return value1!=value2; +// case '1': return value1!=value2; case '2': return value1>value2; case '3': return value1>=value2; case '4': return value1first; - if(PCstats.getFactionRanks().find(toLower(NPCFaction)) != PCstats.getFactionRanks().end()) sameFaction = 1; + if(PCstats.getFactionRanks().find(Misc::toLower(NPCFaction)) != PCstats.getFactionRanks().end()) sameFaction = 1; } if(!selectCompare(comp,sameFaction,select.mI)) return false; } @@ -307,12 +283,12 @@ namespace MWDialogue if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || select.mType==ESM::VT_Long) { - if (!checkGlobal (comp, toLower (name), select.mI)) + if (!checkGlobal (comp, Misc::toLower (name), select.mI)) return false; } else if (select.mType==ESM::VT_Float) { - if (!checkGlobal (comp, toLower (name), select.mF)) + if (!checkGlobal (comp, Misc::toLower (name), select.mF)) return false; } else @@ -326,13 +302,13 @@ namespace MWDialogue if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || select.mType==ESM::VT_Long) { - if (!checkLocal (comp, toLower (name), select.mI, actor, + if (!checkLocal (comp, Misc::toLower (name), select.mI, actor, MWBase::Environment::get().getWorld()->getStore())) return false; } else if (select.mType==ESM::VT_Float) { - if (!checkLocal (comp, toLower (name), select.mF, actor, + if (!checkLocal (comp, Misc::toLower (name), select.mF, actor, MWBase::Environment::get().getWorld()->getStore())) return false; } @@ -345,7 +321,7 @@ namespace MWDialogue case '4'://journal if(select.mType==ESM::VT_Int) { - if(!selectCompare(comp,MWBase::Environment::get().getJournal()->getJournalIndex(toLower(name)),select.mI)) return false; + if(!selectCompare(comp,MWBase::Environment::get().getJournal()->getJournalIndex(Misc::toLower(name)),select.mI)) return false; } else throw std::runtime_error ( @@ -361,7 +337,7 @@ namespace MWDialogue int sum = 0; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (toLower(iter->getCellRef().mRefID) == toLower(name)) + if (Misc::toLower(iter->getCellRef().mRefID) == Misc::toLower(name)) sum += iter->getRefData().getCount(); if(!selectCompare(comp,sum,select.mI)) return false; } @@ -375,7 +351,7 @@ namespace MWDialogue case '7':// not ID if(select.mType==ESM::VT_String ||select.mType==ESM::VT_Int)//bug in morrowind here? it's not a short, it's a string { - int isID = int(toLower(name)==toLower(MWWorld::Class::get (actor).getId (actor))); + int isID = int(Misc::toLower(name)==Misc::toLower(MWWorld::Class::get (actor).getId (actor))); if (selectCompare(comp,!isID,select.mI)) return false; } else @@ -391,7 +367,7 @@ namespace MWDialogue if(select.mType==ESM::VT_Int) { MWWorld::LiveCellRef* npc = actor.get(); - int isFaction = int(toLower(npc->base->mFaction) == toLower(name)); + int isFaction = int(Misc::toLower(npc->base->mFaction) == Misc::toLower(name)); if(selectCompare(comp,!isFaction,select.mI)) return false; } @@ -408,7 +384,7 @@ namespace MWDialogue if(select.mType==ESM::VT_Int) { MWWorld::LiveCellRef* npc = actor.get(); - int isClass = int(toLower(npc->base->mClass) == toLower(name)); + int isClass = int(Misc::toLower(npc->base->mClass) == Misc::toLower(name)); if(selectCompare(comp,!isClass,select.mI)) return false; } @@ -425,7 +401,7 @@ namespace MWDialogue if(select.mType==ESM::VT_Int) { MWWorld::LiveCellRef* npc = actor.get(); - int isRace = int(toLower(npc->base->mRace) == toLower(name)); + int isRace = int(Misc::toLower(npc->base->mRace) == Misc::toLower(name)); if(selectCompare(comp,!isRace,select.mI)) return false; } @@ -438,7 +414,7 @@ namespace MWDialogue case 'B'://not Cell if(select.mType==ESM::VT_Int) { - int isCell = int(toLower(actor.getCell()->cell->mName) == toLower(name)); + int isCell = int(Misc::toLower(actor.getCell()->cell->mName) == Misc::toLower(name)); if(selectCompare(comp,!isCell,select.mI)) return false; } @@ -451,13 +427,13 @@ namespace MWDialogue if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || select.mType==ESM::VT_Long) { - if (checkLocal (comp, toLower (name), select.mI, actor, + if (checkLocal (comp, Misc::toLower (name), select.mI, actor, MWBase::Environment::get().getWorld()->getStore())) return false; } else if (select.mType==ESM::VT_Float) { - if (checkLocal (comp, toLower (name), select.mF, actor, + if (checkLocal (comp, Misc::toLower (name), select.mF, actor, MWBase::Environment::get().getWorld()->getStore())) return false; } @@ -482,7 +458,7 @@ namespace MWDialogue // actor id if (!info.mActor.empty()) - if (toLower (info.mActor)!=MWWorld::Class::get (actor).getId (actor)) + if (Misc::toLower (info.mActor)!=MWWorld::Class::get (actor).getId (actor)) return false; //NPC race @@ -496,7 +472,7 @@ namespace MWDialogue if (!cellRef) return false; - if (toLower (info.mRace)!=toLower (cellRef->base->mRace)) + if (Misc::toLower (info.mRace)!=Misc::toLower (cellRef->base->mRace)) return false; } @@ -511,7 +487,7 @@ namespace MWDialogue if (!cellRef) return false; - if (toLower (info.mClass)!=toLower (cellRef->base->mClass)) + if (Misc::toLower (info.mClass)!=Misc::toLower (cellRef->base->mClass)) return false; } @@ -523,7 +499,7 @@ namespace MWDialogue //MWWorld::Class npcClass = MWWorld::Class::get(actor); MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor); - std::map::iterator it = stats.getFactionRanks().find(toLower(info.mNpcFaction)); + std::map::iterator it = stats.getFactionRanks().find(Misc::toLower(info.mNpcFaction)); if(it!=stats.getFactionRanks().end()) { //check rank @@ -540,7 +516,7 @@ namespace MWDialogue if(!info.mPcFaction.empty()) { MWMechanics::NpcStats stats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - std::map::iterator it = stats.getFactionRanks().find(toLower(info.mPcFaction)); + std::map::iterator it = stats.getFactionRanks().find(Misc::toLower(info.mPcFaction)); if(it!=stats.getFactionRanks().end()) { //check rank @@ -593,13 +569,13 @@ namespace MWDialogue ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { - mDialogueMap[toLower(it->first)] = it->second; + mDialogueMap[Misc::toLower(it->first)] = it->second; } } void DialogueManager::addTopic (const std::string& topic) { - mKnownTopics[toLower(topic)] = true; + mKnownTopics[Misc::toLower(topic)] = true; } void DialogueManager::parseText (std::string text) @@ -753,9 +729,9 @@ namespace MWDialogue { if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) { - mActorKnownTopics.push_back(toLower(it->first)); + mActorKnownTopics.push_back(Misc::toLower(it->first)); //does the player know the topic? - if(mKnownTopics.find(toLower(it->first)) != mKnownTopics.end()) + if(mKnownTopics.find(Misc::toLower(it->first)) != mKnownTopics.end()) { keywordList.push_back(it->first); break; @@ -813,7 +789,7 @@ namespace MWDialogue win->setServices (windowServices); // sort again, because the previous sort was case-sensitive - keywordList.sort(stringCompareNoCase); + keywordList.sort(Misc::stringCompareNoCase); win->setKeywords(keywordList); mChoice = choice; @@ -907,7 +883,7 @@ namespace MWDialogue { MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->askQuestion(question); - mChoiceMap[toLower(question)] = choice; + mChoiceMap[Misc::toLower(question)] = choice; mIsInChoice = true; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index bb3dc67e6..1ac5b2fc6 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -24,19 +24,6 @@ #include "scrollwindow.hpp" #include "spellwindow.hpp" -namespace -{ - std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } -} - namespace MWGui { @@ -284,7 +271,7 @@ namespace MWGui for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { - if (toLower(it->getCellRef().mRefID) == "gold_001") + if (Misc::toLower(it->getCellRef().mRefID) == "gold_001") return it->getRefData().getCount(); } return 0; diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 5e9746b2f..725885e41 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -18,19 +18,6 @@ #include "interpretercontext.hpp" #include "ref.hpp" -namespace -{ - std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } -} - namespace MWScript { namespace Container @@ -78,7 +65,7 @@ namespace MWScript Interpreter::Type_Integer sum = 0; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (toLower(iter->getCellRef().mRefID) == toLower(item)) + if (Misc::toLower(iter->getCellRef().mRefID) == Misc::toLower(item)) sum += iter->getRefData().getCount(); runtime.push (sum); @@ -108,7 +95,7 @@ namespace MWScript for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; ++iter) { - if (toLower(iter->getCellRef().mRefID) == toLower(item)) + if (Misc::toLower(iter->getCellRef().mRefID) == Misc::toLower(item)) { if (iter->getRefData().getCount()<=count) { diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 5c4dd03a4..f736a5253 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -34,12 +34,6 @@ namespace return sum; } - - bool compare_string_ci(std::string str1, std::string str2) - { - boost::algorithm::to_lower(str1); - return str1 == str2; - } } MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {} @@ -81,11 +75,11 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) MWWorld::LiveCellRef *gold = ptr.get(); - if (compare_string_ci(gold->ref.mRefID, "gold_001") - || compare_string_ci(gold->ref.mRefID, "gold_005") - || compare_string_ci(gold->ref.mRefID, "gold_010") - || compare_string_ci(gold->ref.mRefID, "gold_025") - || compare_string_ci(gold->ref.mRefID, "gold_100")) + if (Misc::compare_string_ci(gold->ref.mRefID, "gold_001") + || Misc::compare_string_ci(gold->ref.mRefID, "gold_005") + || Misc::compare_string_ci(gold->ref.mRefID, "gold_010") + || Misc::compare_string_ci(gold->ref.mRefID, "gold_025") + || Misc::compare_string_ci(gold->ref.mRefID, "gold_100")) { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001"); @@ -93,7 +87,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (compare_string_ci((*iter).get()->ref.mRefID, "gold_001")) + if (Misc::compare_string_ci((*iter).get()->ref.mRefID, "gold_001")) { (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); flagAsModified(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c7f0de245..fe8aeb90b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -228,12 +228,12 @@ namespace MWWorld return cell; // didn't work -> now check for regions - std::string cellName2 = ESMS::RecListT::toLower (cellName); + std::string cellName2 = Misc::toLower (cellName); for (ESMS::RecListT::MapType::const_iterator iter (mStore.regions.list.begin()); iter!=mStore.regions.list.end(); ++iter) { - if (ESMS::RecListT::toLower (iter->second.mName)==cellName2) + if (Misc::toLower (iter->second.mName)==cellName2) { if (const ESM::Cell *cell = mStore.cells.searchExtByRegion (iter->first)) return cell; @@ -563,16 +563,6 @@ namespace MWWorld } } - std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } - void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { ESM::Position &pos = ptr.getRefData().getPosition(); @@ -585,7 +575,7 @@ namespace MWWorld if (*currCell != newCell) { if (isPlayer) { if (!newCell.isExterior()) { - changeToInteriorCell(toLower(newCell.cell->mName), pos); + changeToInteriorCell(Misc::toLower(newCell.cell->mName), pos); } else { int cellX = newCell.cell->mData.mX; int cellY = newCell.cell->mData.mY; diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 0b265a566..f9f74244b 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -28,15 +28,6 @@ namespace ESMS virtual int getSize() = 0; virtual void listIdentifier (std::vector& identifier) const = 0; - static std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } }; typedef std::map RecListList; @@ -53,14 +44,14 @@ namespace ESMS // Load one object of this type void load(ESMReader &esm, const std::string &id) { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); list[id2].load(esm); } // Find the given object ID, or return NULL if not found. const X* search(const std::string &id) const { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); typename MapType::const_iterator iter = list.find (id2); @@ -104,7 +95,7 @@ namespace ESMS // Load one object of this type void load(ESMReader &esm, const std::string &id) { - //std::string id2 = toLower (id); + //std::string id2 = Misc::toLower (id); list[id].load(esm); } @@ -112,12 +103,12 @@ namespace ESMS // Find the given object ID, or return NULL if not found. const X* search(const std::string &id) const { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); for (typename MapType::const_iterator iter = list.begin(); iter != list.end(); ++iter) { - if (toLower(iter->first) == id2) + if (Misc::toLower(iter->first) == id2) return &iter->second; } @@ -127,12 +118,12 @@ namespace ESMS // non-const version X* search(const std::string &id) { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); for (typename MapType::iterator iter = list.begin(); iter != list.end(); ++iter) { - if (toLower(iter->first) == id2) + if (Misc::toLower(iter->first) == id2) return &iter->second; } @@ -172,7 +163,7 @@ namespace ESMS // Load one object of this type void load(ESMReader &esm, const std::string &id) { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); list[id2].mId = id2; list[id2].load(esm); } @@ -180,7 +171,7 @@ namespace ESMS // Find the given object ID, or return NULL if not found. const X* search(const std::string &id) const { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); typename MapType::const_iterator iter = list.find (id2); @@ -223,7 +214,7 @@ namespace ESMS void load(ESMReader &esm, const std::string &id) { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); X& ref = list[id2]; ref.mId = id; @@ -233,7 +224,7 @@ namespace ESMS // Find the given object ID, or return NULL if not found. const X* search(const std::string &id) const { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); typename MapType::const_iterator iter = list.find (id2); @@ -440,7 +431,7 @@ namespace ESMS { for (ExtCells::const_iterator iter = extCells.begin(); iter!=extCells.end(); ++iter) { - if (toLower (iter->second->mName) == toLower (id)) + if (Misc::toLower (iter->second->mName) == Misc::toLower (id)) return iter->second; } @@ -449,10 +440,10 @@ namespace ESMS const ESM::Cell *searchExtByRegion (const std::string& id) const { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); for (ExtCells::const_iterator iter = extCells.begin(); iter!=extCells.end(); ++iter) - if (toLower (iter->second->mRegion)==id) + if (Misc::toLower (iter->second->mRegion)==id) return iter->second; return 0; @@ -586,7 +577,7 @@ namespace ESMS X ref; ref.load (esm); - std::string realId = toLower (ref.mData.mName.toString()); + std::string realId = Misc::toLower (ref.mData.mName.toString()); std::swap (list[realId], ref); } @@ -594,7 +585,7 @@ namespace ESMS // Find the given object ID, or return NULL if not found. const X* search(const std::string &id) const { - std::string id2 = toLower (id); + std::string id2 = Misc::toLower (id); typename MapType::const_iterator iter = list.find (id2); diff --git a/components/misc/stringops.cpp b/components/misc/stringops.cpp index 53eed1fdc..f209bf46b 100644 --- a/components/misc/stringops.cpp +++ b/components/misc/stringops.cpp @@ -1,7 +1,14 @@ #include "stringops.hpp" +#include +#include +#include + #include #include +#include + + namespace Misc { @@ -61,4 +68,34 @@ bool iends(const char* str1, const char* str2) return strcasecmp(str2, str1+len1-len2) == 0; } +std::string toLower (const std::string& name) +{ + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; +} + +bool stringCompareNoCase (std::string first, std::string second) +{ + unsigned int i=0; + while ( (itolower(second[i])) return false; + ++i; + } + if (first.length() + namespace Misc { @@ -16,6 +18,13 @@ bool ibegins(const char* str1, const char* str2); /// Case insensitive, returns true if str1 ends with substring str2 bool iends(const char* str1, const char* str2); + +std::string toLower (const std::string& name); + +bool stringCompareNoCase (std::string first, std::string second); + +bool compare_string_ci (std::string first, std::string second); + } #endif From c75a5ae212bc01d1b3d37ffcf0f3cf879f7775a4 Mon Sep 17 00:00:00 2001 From: eduard Date: Fri, 28 Dec 2012 18:05:52 +0100 Subject: [PATCH 197/916] string compare and tolower --- apps/openmw/mwworld/containerstore.cpp | 18 ++++++++++++------ components/misc/stringops.cpp | 7 +------ components/misc/stringops.hpp | 5 ++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index f736a5253..5c4dd03a4 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -34,6 +34,12 @@ namespace return sum; } + + bool compare_string_ci(std::string str1, std::string str2) + { + boost::algorithm::to_lower(str1); + return str1 == str2; + } } MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {} @@ -75,11 +81,11 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) MWWorld::LiveCellRef *gold = ptr.get(); - if (Misc::compare_string_ci(gold->ref.mRefID, "gold_001") - || Misc::compare_string_ci(gold->ref.mRefID, "gold_005") - || Misc::compare_string_ci(gold->ref.mRefID, "gold_010") - || Misc::compare_string_ci(gold->ref.mRefID, "gold_025") - || Misc::compare_string_ci(gold->ref.mRefID, "gold_100")) + if (compare_string_ci(gold->ref.mRefID, "gold_001") + || compare_string_ci(gold->ref.mRefID, "gold_005") + || compare_string_ci(gold->ref.mRefID, "gold_010") + || compare_string_ci(gold->ref.mRefID, "gold_025") + || compare_string_ci(gold->ref.mRefID, "gold_100")) { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001"); @@ -87,7 +93,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (Misc::compare_string_ci((*iter).get()->ref.mRefID, "gold_001")) + if (compare_string_ci((*iter).get()->ref.mRefID, "gold_001")) { (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); flagAsModified(); diff --git a/components/misc/stringops.cpp b/components/misc/stringops.cpp index f209bf46b..51cf2105a 100644 --- a/components/misc/stringops.cpp +++ b/components/misc/stringops.cpp @@ -6,7 +6,6 @@ #include #include -#include @@ -92,10 +91,6 @@ bool stringCompareNoCase (std::string first, std::string second) else return false; } -bool compare_string_ci(std::string str1, std::string str2) -{ - boost::algorithm::to_lower(str1); - return str1 == str2; -} + } diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 6403a7128..4dbfd40d4 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -18,13 +18,12 @@ bool ibegins(const char* str1, const char* str2); /// Case insensitive, returns true if str1 ends with substring str2 bool iends(const char* str1, const char* str2); - +/// std::string toLower (const std::string& name); +/// Case fold compare bool stringCompareNoCase (std::string first, std::string second); -bool compare_string_ci (std::string first, std::string second); - } #endif From ade4ec04532382fec14d6963324be55731911672 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 28 Dec 2012 19:01:47 +0100 Subject: [PATCH 198/916] fix texture edge bleeding due to wrong addressing mode --- apps/openmw/mwrender/videoplayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 8e05a4f82..2d24edc51 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1019,7 +1019,8 @@ VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) mVideoMaterial->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); mVideoMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); mVideoMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(); - } + mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureAddressingMode(Ogre::TextureUnitState::TAM_CLAMP); + } mVideoMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("black.png"); Ogre::MaterialPtr blackMaterial = Ogre::MaterialManager::getSingleton().getByName("BlackBarsMaterial", "General"); From 1dd9276cebdd6035f6c0071d5dea1a28b873d4d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 28 Dec 2012 11:26:41 -0800 Subject: [PATCH 199/916] Add missing decoder method declarations --- apps/openmw/mwsound/audiere_decoder.hpp | 1 + apps/openmw/mwsound/mpgsnd_decoder.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/openmw/mwsound/audiere_decoder.hpp b/apps/openmw/mwsound/audiere_decoder.hpp index 8623a3f2c..91c07ccac 100644 --- a/apps/openmw/mwsound/audiere_decoder.hpp +++ b/apps/openmw/mwsound/audiere_decoder.hpp @@ -21,6 +21,7 @@ namespace MWSound virtual void open(const std::string &fname); virtual void close(); + virtual std::string getName(); virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual size_t read(char *buffer, size_t bytes); diff --git a/apps/openmw/mwsound/mpgsnd_decoder.hpp b/apps/openmw/mwsound/mpgsnd_decoder.hpp index 52c37bb87..be52f6f49 100644 --- a/apps/openmw/mwsound/mpgsnd_decoder.hpp +++ b/apps/openmw/mwsound/mpgsnd_decoder.hpp @@ -34,6 +34,7 @@ namespace MWSound virtual void open(const std::string &fname); virtual void close(); + virtual std::string getName(); virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual size_t read(char *buffer, size_t bytes); From bed8fb69e65048166cef300ffe2bbe2354def3d3 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Fri, 28 Dec 2012 22:26:21 +0000 Subject: [PATCH 200/916] added bounty related scripting functions --- apps/openmw/mwscript/docs/vmformat.txt | 5 ++- apps/openmw/mwscript/statsextensions.cpp | 52 ++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 835a3e3ff..df1a52329 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -291,8 +291,11 @@ op 0x20001e8: RaiseRank op 0x20001e9: RaiseRank, explicit op 0x20001ea: LowerRank op 0x20001eb: LowerRank, explicit +op 0x20001ec: GetPCCrimeLevel +op 0x20001ed: SetPCCrimeLevel +op 0x20001ee: SetPCCrimeLevel -opcodes 0x20001ec-0x3ffffff unused +opcodes 0x20001ef-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index c67782168..9e630aedf 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -392,6 +392,46 @@ namespace MWScript } }; + class OpGetPCCrimeLevel : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + runtime.push (static_cast (MWWorld::Class::get (player).getNpcStats (player).getBounty())); + } + }; + + class OpSetPCCrimeLevel : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + MWWorld::Class::get (player).getNpcStats (player).setBounty(runtime[0].mFloat); + runtime.pop(); + } + }; + + class OpModPCCrimeLevel : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + MWWorld::Class::get (player).getNpcStats (player).setBounty(runtime[0].mFloat + MWWorld::Class::get (player).getNpcStats (player).getBounty()); + runtime.pop(); + } + }; + template class OpAddSpell : public Interpreter::Opcode0 { @@ -1016,6 +1056,10 @@ namespace MWScript const int opcodeModSkill = 0x20000fa; const int opcodeModSkillExplicit = 0x2000115; + const int opcodeGetPCCrimeLevel = 0x20001ec; + const int opcodeSetPCCrimeLevel = 0x20001ed; + const int opcodeModPCCrimeLevel = 0x20001ee; + const int opcodeAddSpell = 0x2000147; const int opcodeAddSpellExplicit = 0x2000148; const int opcodeRemoveSpell = 0x2000149; @@ -1141,6 +1185,10 @@ namespace MWScript opcodeModSkill+i, opcodeModSkillExplicit+i); } + extensions.registerFunction ("getpccrimelevel", 'f', "", opcodeGetPCCrimeLevel); + extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel); + extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); + extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, opcodeRemoveSpellExplicit); @@ -1235,6 +1283,10 @@ namespace MWScript interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkill (i)); } + interpreter.installSegment5 (opcodeGetPCCrimeLevel, new OpGetPCCrimeLevel); + interpreter.installSegment5 (opcodeSetPCCrimeLevel, new OpSetPCCrimeLevel); + interpreter.installSegment5 (opcodeModPCCrimeLevel, new OpModPCCrimeLevel); + interpreter.installSegment5 (opcodeAddSpell, new OpAddSpell); interpreter.installSegment5 (opcodeAddSpellExplicit, new OpAddSpell); interpreter.installSegment5 (opcodeRemoveSpell, new OpRemoveSpell); From 8d4afe3bf5abfe2703a782eb5c7338a2d4efb0ce Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 28 Dec 2012 23:45:13 +0100 Subject: [PATCH 201/916] post merge fix --- apps/opencs/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 1cfb5d9a9..abbc953ca 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -6,6 +6,7 @@ set (OPENCS_SRC model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp + model/world/columnbase.cpp model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp model/tools/mandatoryid.cpp model/tools/reportmodel.cpp @@ -26,7 +27,7 @@ set (OPENCS_HDR model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp - model/world/commands.hpp + model/world/commands.hpp model/world/columnbase.hpp model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp model/tools/mandatoryid.hpp model/tools/reportmodel.hpp From 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 29 Dec 2012 09:23:06 +0100 Subject: [PATCH 202/916] updated credits file --- credits.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/credits.txt b/credits.txt index 84a596a6b..72451c3d0 100644 --- a/credits.txt +++ b/credits.txt @@ -37,7 +37,7 @@ Pieter van der Kloet (pvdk) Roman Melnik (Kromgart) Sebastian Wick (swick) Sylvain T. (Garvek) - +Tom Mason (wheybags) Packagers: Alexander Olofsson (Ace) - Windows From b2203d22fce8483ed2cbce48a55cb65d175445c9 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 29 Dec 2012 15:22:29 +0100 Subject: [PATCH 203/916] mwiniimporter: added fallback values Ugly comments included. I will merge it on another branch to clean this up later. --- apps/mwiniimporter/importer.cpp | 564 ++++++++++++++++++++++++++++++++ 1 file changed, 564 insertions(+) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 19b69794f..1236dcaf0 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -18,8 +18,572 @@ MwIniImporter::MwIniImporter() { 0, 0 } }; const char *fallback[] = { + + /* + "Fonts:Font 0", + "Fonts:Font 1", + "Fonts:Font 2", + */ + + /* + "FontColor:color_normal", + "FontColor:color_normal_over", + "FontColor:color_normal_pressed", + "FontColor:color_active", + "FontColor:color_active_over", + "FontColor:color_active_pressed", + "FontColor:color_disabled", + "FontColor:color_disabled_over", + "FontColor:color_disabled_pressed", + "FontColor:color_link", + "FontColor:color_link_over", + "FontColor:color_link_pressed", + "FontColor:color_journal_link", + "FontColor:color_journal_link_over", + "FontColor:color_journal_link_pressed", + "FontColor:color_journal_topic", + "FontColor:color_journal_topic_over", + "FontColor:color_journal_topic_pressed", + "FontColor:color_answer", + "FontColor:color_answer_over", + "FontColor:color_answer_pressed", + "FontColor:color_header", + "FontColor:color_notify", + "FontColor:color_big_normal", + "FontColor:color_big_normal_over", + "FontColor:color_big_normal_pressed", + "FontColor:color_big_link", + "FontColor:color_big_link_over", + "FontColor:color_big_link_pressed", + "FontColor:color_big_answer", + "FontColor:color_big_answer_over", + "FontColor:color_big_answer_pressed", + "FontColor:color_big_header", + "FontColor:color_big_notify", + "FontColor:color_background", + "FontColor:color_focus", + "FontColor:color_health", + "FontColor:color_magic", + "FontColor:color_fatigue", + "FontColor:color_misc", + "FontColor:color_weapon_fill", + "FontColor:color_magic_fill", + "FontColor:color_positive", + "FontColor:color_negative", + "FontColor:color_count", + */ + + /* + "Cursors:Cursor 0", + "Cursors:Cursor 1", + "Cursors:Cursor 2", + "Cursors:Cursor 3", + "Cursors:Cursor 4", + */ + + // level up messages + // not used for now + "Level Up:Level2", + "Level Up:Level3", + "Level Up:Level4", + "Level Up:Level5", + "Level Up:Level6", + "Level Up:Level7", + "Level Up:Level8", + "Level Up:Level9", + "Level Up:Level10", + "Level Up:Level11", + "Level Up:Level12", + "Level Up:Level13", + "Level Up:Level14", + "Level Up:Level15", + "Level Up:Level16", + "Level Up:Level17", + "Level Up:Level18", + "Level Up:Level19", + "Level Up:Level20", + "Level Up:Default", + + // character creation multiple choice test + // hardcoded in mwgui/charactercreation.cpp + "Question 1:Question", + "Question 1:AnswerOne", + "Question 1:AnswerTwo", + "Question 1:AnswerThree", + "Question 1:Sound", + "Question 2:Question", + "Question 2:AnswerOne", + "Question 2:AnswerTwo", + "Question 2:AnswerThree", + "Question 2:Sound", + "Question 3:Question", + "Question 3:AnswerOne", + "Question 3:AnswerTwo", + "Question 3:AnswerThree", + "Question 3:Sound", + "Question 4:Question", + "Question 4:AnswerOne", + "Question 4:AnswerTwo", + "Question 4:AnswerThree", + "Question 4:Sound", + "Question 5:Question", + "Question 5:AnswerOne", + "Question 5:AnswerTwo", + "Question 5:AnswerThree", + "Question 5:Sound", + "Question 6:Question", + "Question 6:AnswerOne", + "Question 6:AnswerTwo", + "Question 6:AnswerThree", + "Question 6:Sound", + "Question 7:Question", + "Question 7:AnswerOne", + "Question 7:AnswerTwo", + "Question 7:AnswerThree", + "Question 7:Sound", + "Question 8:Question", + "Question 8:AnswerOne", + "Question 8:AnswerTwo", + "Question 8:AnswerThree", + "Question 8:Sound", + "Question 9:Question", + "Question 9:AnswerOne", + "Question 9:AnswerTwo", + "Question 9:AnswerThree", + "Question 9:Sound", + "Question 10:Question", + "Question 10:AnswerOne", + "Question 10:AnswerTwo", + "Question 10:AnswerThree", + "Question 10:Sound", + + // blood textures and models + // not used for now + "Blood:Model 0", + "Blood:Model 1", + "Blood:Model 2", + "Blood:Texture 0", + "Blood:Texture 1", + "Blood:Texture 2", + "Blood:Texture Name 0", + "Blood:Texture Name 1", + "Blood:Texture Name 2", + + // movies + // not used for now + "Movies:Company Logo", + "Movies:Morrowind Logo", + "Movies:New Game", + "Movies:Loading", + "Movies:Options Menu", + + // weather related values + // hardcoded in mwworld/wheather.cpp + // Some are easy to replace, others are used as magic number + + // globals + "Weather Thunderstorm:Thunder Sound ID 0", + "Weather Thunderstorm:Thunder Sound ID 1", + "Weather Thunderstorm:Thunder Sound ID 2", + "Weather Thunderstorm:Thunder Sound ID 3", "Weather:Sunrise Time", "Weather:Sunset Time", + "Weather:Sunrise Duration", + "Weather:Sunset Duration", + "Weather:Hours Between Weather Changes", // AKA weather update time + "Weather Thunderstorm:Thunder Frequency", + "Weather Thunderstorm:Thunder Threshold", + // thunder sound delay? + + "Weather Clear:Cloud Texture", + "Weather Clear:Clouds Maximum Percent", + "Weather Clear:Transition Delta", + "Weather Clear:Sky Sunrise Color", + "Weather Clear:Sky Day Color", + "Weather Clear:Sky Sunset Color", + "Weather Clear:Sky Night Color", + "Weather Clear:Fog Sunrise Color", + "Weather Clear:Fog Day Color", + "Weather Clear:Fog Sunset Color", + "Weather Clear:Fog Night Color", + "Weather Clear:Ambient Sunrise Color", + "Weather Clear:Ambient Day Color", + "Weather Clear:Ambient Sunset Color", + "Weather Clear:Ambient Night Color", + "Weather Clear:Sun Sunrise Color", + "Weather Clear:Sun Day Color", + "Weather Clear:Sun Sunset Color", + "Weather Clear:Sun Night Color", + "Weather Clear:Sun Disc Sunset Color", + "Weather Clear:Land Fog Day Depth", + "Weather Clear:Land Fog Night Depth", + "Weather Clear:Wind Speed", + "Weather Clear:Cloud Speed", + "Weather Clear:Glare View", + + "Weather Cloudy:Cloud Texture", + "Weather Cloudy:Clouds Maximum Percent", + "Weather Cloudy:Transition Delta", + "Weather Cloudy:Sky Sunrise Color", + "Weather Cloudy:Sky Day Color", + "Weather Cloudy:Sky Sunset Color", + "Weather Cloudy:Sky Night Color", + "Weather Cloudy:Fog Sunrise Color", + "Weather Cloudy:Fog Day Color", + "Weather Cloudy:Fog Sunset Color", + "Weather Cloudy:Fog Night Color", + "Weather Cloudy:Ambient Sunrise Color", + "Weather Cloudy:Ambient Day Color", + "Weather Cloudy:Ambient Sunset Color", + "Weather Cloudy:Ambient Night Color", + "Weather Cloudy:Sun Sunrise Color", + "Weather Cloudy:Sun Day Color", + "Weather Cloudy:Sun Sunset Color", + "Weather Cloudy:Sun Night Color", + "Weather Cloudy:Sun Disc Sunset Color", + "Weather Cloudy:Land Fog Day Depth", + "Weather Cloudy:Land Fog Night Depth", + "Weather Cloudy:Wind Speed", + "Weather Cloudy:Cloud Speed", + "Weather Cloudy:Glare View", + + "Weather Foggy:Cloud Texture", + "Weather Foggy:Clouds Maximum Percent", + "Weather Foggy:Transition Delta", + "Weather Foggy:Sky Sunrise Color", + "Weather Foggy:Sky Day Color", + "Weather Foggy:Sky Sunset Color", + "Weather Foggy:Sky Night Color", + "Weather Foggy:Fog Sunrise Color", + "Weather Foggy:Fog Day Color", + "Weather Foggy:Fog Sunset Color", + "Weather Foggy:Fog Night Color", + "Weather Foggy:Ambient Sunrise Color", + "Weather Foggy:Ambient Day Color", + "Weather Foggy:Ambient Sunset Color", + "Weather Foggy:Ambient Night Color", + "Weather Foggy:Sun Sunrise Color", + "Weather Foggy:Sun Day Color", + "Weather Foggy:Sun Sunset Color", + "Weather Foggy:Sun Night Color", + "Weather Foggy:Sun Disc Sunset Color", + "Weather Foggy:Land Fog Day Depth", + "Weather Foggy:Land Fog Night Depth", + "Weather Foggy:Wind Speed", + "Weather Foggy:Cloud Speed", + "Weather Foggy:Glare View", + + "Weather Thunderstorm:Cloud Texture", + "Weather Thunderstorm:Clouds Maximum Percent", + "Weather Thunderstorm:Transition Delta", + "Weather Thunderstorm:Sky Sunrise Color", + "Weather Thunderstorm:Sky Day Color", + "Weather Thunderstorm:Sky Sunset Color", + "Weather Thunderstorm:Sky Night Color", + "Weather Thunderstorm:Fog Sunrise Color", + "Weather Thunderstorm:Fog Day Color", + "Weather Thunderstorm:Fog Sunset Color", + "Weather Thunderstorm:Fog Night Color", + "Weather Thunderstorm:Ambient Sunrise Color", + "Weather Thunderstorm:Ambient Day Color", + "Weather Thunderstorm:Ambient Sunset Color", + "Weather Thunderstorm:Ambient Night Color", + "Weather Thunderstorm:Sun Sunrise Color", + "Weather Thunderstorm:Sun Day Color", + "Weather Thunderstorm:Sun Sunset Color", + "Weather Thunderstorm:Sun Night Color", + "Weather Thunderstorm:Sun Disc Sunset Color", + "Weather Thunderstorm:Land Fog Day Depth", + "Weather Thunderstorm:Land Fog Night Depth", + "Weather Thunderstorm:Wind Speed", + "Weather Thunderstorm:Cloud Speed", + "Weather Thunderstorm:Glare View", + "Weather Thunderstorm:Rain Loop Sound ID", + + "Weather Rain:Cloud Texture", + "Weather Rain:Clouds Maximum Percent", + "Weather Rain:Transition Delta", + "Weather Rain:Sky Sunrise Color", + "Weather Rain:Sky Day Color", + "Weather Rain:Sky Sunset Color", + "Weather Rain:Sky Night Color", + "Weather Rain:Fog Sunrise Color", + "Weather Rain:Fog Day Color", + "Weather Rain:Fog Sunset Color", + "Weather Rain:Fog Night Color", + "Weather Rain:Ambient Sunrise Color", + "Weather Rain:Ambient Day Color", + "Weather Rain:Ambient Sunset Color", + "Weather Rain:Ambient Night Color", + "Weather Rain:Sun Sunrise Color", + "Weather Rain:Sun Day Color", + "Weather Rain:Sun Sunset Color", + "Weather Rain:Sun Night Color", + "Weather Rain:Sun Disc Sunset Color", + "Weather Rain:Land Fog Day Depth", + "Weather Rain:Land Fog Night Depth", + "Weather Rain:Wind Speed", + "Weather Rain:Cloud Speed", + "Weather Rain:Glare View", + "Weather Rain:Rain Loop Sound ID", + + "Weather Overcast:Cloud Texture", + "Weather Overcast:Clouds Maximum Percent", + "Weather Overcast:Transition Delta", + "Weather Overcast:Sky Sunrise Color", + "Weather Overcast:Sky Day Color", + "Weather Overcast:Sky Sunset Color", + "Weather Overcast:Sky Night Color", + "Weather Overcast:Fog Sunrise Color", + "Weather Overcast:Fog Day Color", + "Weather Overcast:Fog Sunset Color", + "Weather Overcast:Fog Night Color", + "Weather Overcast:Ambient Sunrise Color", + "Weather Overcast:Ambient Day Color", + "Weather Overcast:Ambient Sunset Color", + "Weather Overcast:Ambient Night Color", + "Weather Overcast:Sun Sunrise Color", + "Weather Overcast:Sun Day Color", + "Weather Overcast:Sun Sunset Color", + "Weather Overcast:Sun Night Color", + "Weather Overcast:Sun Disc Sunset Color", + "Weather Overcast:Land Fog Day Depth", + "Weather Overcast:Land Fog Night Depth", + "Weather Overcast:Wind Speed", + "Weather Overcast:Cloud Speed", + "Weather Overcast:Glare View", + + "Weather Ashstorm:Cloud Texture", + "Weather Ashstorm:Clouds Maximum Percent", + "Weather Ashstorm:Transition Delta", + "Weather Ashstorm:Sky Sunrise Color", + "Weather Ashstorm:Sky Day Color", + "Weather Ashstorm:Sky Sunset Color", + "Weather Ashstorm:Sky Night Color", + "Weather Ashstorm:Fog Sunrise Color", + "Weather Ashstorm:Fog Day Color", + "Weather Ashstorm:Fog Sunset Color", + "Weather Ashstorm:Fog Night Color", + "Weather Ashstorm:Ambient Sunrise Color", + "Weather Ashstorm:Ambient Day Color", + "Weather Ashstorm:Ambient Sunset Color", + "Weather Ashstorm:Ambient Night Color", + "Weather Ashstorm:Sun Sunrise Color", + "Weather Ashstorm:Sun Day Color", + "Weather Ashstorm:Sun Sunset Color", + "Weather Ashstorm:Sun Night Color", + "Weather Ashstorm:Sun Disc Sunset Color", + "Weather Ashstorm:Land Fog Day Depth", + "Weather Ashstorm:Land Fog Night Depth", + "Weather Ashstorm:Wind Speed", + "Weather Ashstorm:Cloud Speed", + "Weather Ashstorm:Glare View", + "Weather Ashstorm:Ambient Loop Sound ID", + + "Weather Blight:Cloud Texture", + "Weather Blight:Clouds Maximum Percent", + "Weather Blight:Transition Delta", + "Weather Blight:Sky Sunrise Color", + "Weather Blight:Sky Day Color", + "Weather Blight:Sky Sunset Color", + "Weather Blight:Sky Night Color", + "Weather Blight:Fog Sunrise Color", + "Weather Blight:Fog Day Color", + "Weather Blight:Fog Sunset Color", + "Weather Blight:Fog Night Color", + "Weather Blight:Ambient Sunrise Color", + "Weather Blight:Ambient Day Color", + "Weather Blight:Ambient Sunset Color", + "Weather Blight:Ambient Night Color", + "Weather Blight:Sun Sunrise Color", + "Weather Blight:Sun Day Color", + "Weather Blight:Sun Sunset Color", + "Weather Blight:Sun Night Color", + "Weather Blight:Sun Disc Sunset Color", + "Weather Blight:Land Fog Day Depth", + "Weather Blight:Land Fog Night Depth", + "Weather Blight:Wind Speed", + "Weather Blight:Cloud Speed", + "Weather Blight:Glare View", + "Weather Blight:Ambient Loop Sound ID", + + // not used for now (todo) + "Weather Blight:Disease Chance", + + // for Bloodmoon + "Weather Snow:Cloud Texture", + "Weather Snow:Clouds Maximum Percent", + "Weather Snow:Transition Delta", + "Weather Snow:Sky Sunrise Color", + "Weather Snow:Sky Day Color", + "Weather Snow:Sky Sunset Color", + "Weather Snow:Sky Night Color", + "Weather Snow:Fog Sunrise Color", + "Weather Snow:Fog Day Color", + "Weather Snow:Fog Sunset Color", + "Weather Snow:Fog Night Color", + "Weather Snow:Ambient Sunrise Color", + "Weather Snow:Ambient Day Color", + "Weather Snow:Ambient Sunset Color", + "Weather Snow:Ambient Night Color", + "Weather Snow:Sun Sunrise Color", + "Weather Snow:Sun Day Color", + "Weather Snow:Sun Sunset Color", + "Weather Snow:Sun Night Color", + "Weather Snow:Sun Disc Sunset Color", + "Weather Snow:Land Fog Day Depth", + "Weather Snow:Land Fog Night Depth", + "Weather Snow:Wind Speed", + "Weather Snow:Cloud Speed", + "Weather Snow:Glare View", + + // for Bloodmoon + "Weather Blizzard:Cloud Texture", + "Weather Blizzard:Clouds Maximum Percent", + "Weather Blizzard:Transition Delta", + "Weather Blizzard:Sky Sunrise Color", + "Weather Blizzard:Sky Day Color", + "Weather Blizzard:Sky Sunset Color", + "Weather Blizzard:Sky Night Color", + "Weather Blizzard:Fog Sunrise Color", + "Weather Blizzard:Fog Day Color", + "Weather Blizzard:Fog Sunset Color", + "Weather Blizzard:Fog Night Color", + "Weather Blizzard:Ambient Sunrise Color", + "Weather Blizzard:Ambient Day Color", + "Weather Blizzard:Ambient Sunset Color", + "Weather Blizzard:Ambient Night Color", + "Weather Blizzard:Sun Sunrise Color", + "Weather Blizzard:Sun Day Color", + "Weather Blizzard:Sun Sunset Color", + "Weather Blizzard:Sun Night Color", + "Weather Blizzard:Sun Disc Sunset Color", + "Weather Blizzard:Land Fog Day Depth", + "Weather Blizzard:Land Fog Night Depth", + "Weather Blizzard:Wind Speed", + "Weather Blizzard:Cloud Speed", + "Weather Blizzard:Glare View", + "Weather Blizzard:Ambient Loop Sound ID", + + // not used + "Weather Clear:Ambient Loop Sound ID", + "Weather Cloudy:Ambient Loop Sound ID", + "Weather Foggy:Ambient Loop Sound ID", + "Weather Overcast:Ambient Loop Sound ID", + "Weather Snow:Ambient Loop Sound ID", + // + "Weather Ashstorm:Storm Threshold", + "Weather Blight:Storm Threshold", + "Weather Snow:Snow Threshold", + "Weather Blizzard:Storm Threshold", + // + "Weather Snow:Snow Diameter", + "Weather Snow:Snow Height Min", + "Weather Snow:Snow Height Max", + "Weather Snow:Snow Entrance Speed", + "Weather Snow:Max Snowflakes", + // + "Weather:EnvReduceColor", + "Weather:LerpCloseColor", + "Weather:BumpFadeColor", + "Weather:AlphaReduce", + "Weather:Minimum Time Between Environmental Sounds", + "Weather:Maximum Time Between Environmental Sounds", + "Weather:Sun Glare Fader Max", + "Weather:Sun Glare Fader Angle Max", + "Weather:Sun Glare Fader Color", + "Weather:Timescale Clouds", + "Weather:Precip Gravity", + "Weather:Rain Ripples", + "Weather:Rain Ripple Radius", + "Weather:Rain Ripples Per Drop", + "Weather:Rain Ripple Scale", + "Weather:Rain Ripple Speed", + "Weather:Fog Depth Change Speed", + "Weather:Sky Pre-Sunrise Time", + "Weather:Sky Post-Sunrise Time", + "Weather:Sky Pre-Sunset Time", + "Weather:Sky Post-Sunset Time", + "Weather:Ambient Pre-Sunrise Time", + "Weather:Ambient Post-Sunrise Time", + "Weather:Ambient Pre-Sunset Time", + "Weather:Ambient Post-Sunset Time", + "Weather:Fog Pre-Sunrise Time", + "Weather:Fog Post-Sunrise Time", + "Weather:Fog Pre-Sunset Time", + "Weather:Fog Post-Sunset Time", + "Weather:Sun Pre-Sunrise Time", + "Weather:Sun Post-Sunrise Time", + "Weather:Sun Pre-Sunset Time", + "Weather:Sun Post-Sunset Time", + "Weather:Stars Post-Sunset Start", + "Weather:Stars Pre-Sunrise Finish", + "Weather:Stars Fading Duration", + "Weather:Snow Ripples", + "Weather:Snow Ripple Radius", + "Weather:Snow Ripples Per Flake", + "Weather:Snow Ripple Scale", + "Weather:Snow Ripple Speed", + "Weather:Snow Gravity Scale", + "Weather:Snow High Kill", + "Weather:Snow Low Kill", + // + "Weather Rain:Using Precip", + "Weather Rain:Rain Diameter", + "Weather Rain:Rain Height Min", + "Weather Rain:Rain Height Max", + "Weather Rain:Rain Threshold", + "Weather Rain:Rain Entrance Speed", + "Weather Rain:Ambient Loop Sound ID", + "Weather Rain:Max Raindrops", + // + "Weather Thunderstorm:Using Precip", + "Weather Thunderstorm:Rain Diameter", + "Weather Thunderstorm:Rain Height Min", + "Weather Thunderstorm:Rain Height Max", + "Weather Thunderstorm:Rain Threshold", + "Weather Thunderstorm:Max Raindrops", + "Weather Thunderstorm:Rain Entrance Speed", + "Weather Thunderstorm:Ambient Loop Sound ID", + "Weather Thunderstorm:Flash Decrement", + + // moons + + // these are hardcoded in mwworld/weather.cpp + // l.642..665 (masser_angle_fade) + "Moons:Secunda Fade Start Angle", // = 50 + "Moons:Secunda Fade End Angle", // = 40 + "Moons:Masser Fade Start Angle", // = 50 + "Moons:Masser Fade End Angle", // = 30 + + // hardcoded in weather.cpp l.635 to 641 (hour_fade) + "Moons:Secunda Fade In Start", // = 14 + "Moons:Secunda Fade In Finish", // = 15 + "Moons:Secunda Fade Out Start", // = 7 + "Moons:Secunda Fade Out Finish", // = 10 + + // same values as Secunda + "Moons:Masser Fade In Start", + "Moons:Masser Fade In Finish", + "Moons:Masser Fade Out Start", + "Moons:Masser Fade Out Finish", + + // color code hardcoded in mwrender/sky.cpp (l.417, mMoonRed) + // as float values (divided by 255) + "Moons:Script Color", + + // not used + "Moons:Secunda Size", + "Moons:Secunda Axis Offset", + "Moons:Secunda Speed", + "Moons:Secunda Daily Increment", + "Moons:Secunda Moon Shadow Early Fade Angle", + "Moons:Masser Size", + "Moons:Masser Axis Offset", + "Moons:Masser Speed", + "Moons:Masser Daily Increment", + "Moons:Masser Moon Shadow Early Fade Angle", + 0 }; From 9d043d0193b3a35c2f7bb0946c39f20469f771c8 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 29 Dec 2012 17:15:53 +0100 Subject: [PATCH 204/916] mwiniimporter: fix string cutting --- apps/mwiniimporter/importer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 1236dcaf0..0bf0ae4ec 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -618,7 +618,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) { if(line[0] == '[') { if(line.length() > 2) { - section = line.substr(1, line.length()-3); + section = line.substr(1, line.length()-2); } continue; } @@ -711,7 +711,7 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) { std::string value(*it); std::replace( value.begin(), value.end(), ' ', '_' ); std::replace( value.begin(), value.end(), ':', '_' ); - value.append(",").append(vc->substr(0,vc->length()-1)); + value.append(",").append(vc->substr(0,vc->length())); insertMultistrmap(cfg, "fallback", value); } } From fb25f407fbcd2e392e63a8c1f1b7393ecfe65e01 Mon Sep 17 00:00:00 2001 From: eduard Date: Sun, 30 Dec 2012 13:37:19 +0100 Subject: [PATCH 205/916] dialoguemanager conflict --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 533 +----------------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 1 + 2 files changed, 4 insertions(+), 530 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 743db9a43..8e74894b9 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -43,89 +43,6 @@ namespace { -<<<<<<< HEAD - template - bool selectCompare (char comp, T1 value1, T2 value2) - { - switch (comp) - { - case '0': return value1==value2; -// case '1': return value1!=value2; - case '2': return value1>value2; - case '3': return value1>=value2; - case '4': return value1 - bool checkLocal (char comp, const std::string& name, T value, const MWWorld::Ptr& actor, - const ESMS::ESMStore& store) - { - std::string scriptName = MWWorld::Class::get (actor).getScript (actor); - - if (scriptName.empty()) - return false; // no script - - const ESM::Script *script = store.scripts.find (scriptName); - - int i = 0; - - for (; i (script->mVarNames.size()); ++i) - if (script->mVarNames[i]==name) - break; - - if (i>=static_cast (script->mVarNames.size())) - return false; // script does not have a variable of this name - - const MWScript::Locals& locals = actor.getRefData().getLocals(); - - if (imData.mNumShorts) - return selectCompare (comp, locals.mShorts[i], value); - else - i -= script->mData.mNumShorts; - - if (imData.mNumLongs) - return selectCompare (comp, locals.mLongs[i], value); - else - i -= script->mData.mNumShorts; - - return selectCompare (comp, locals.mFloats.at (i), value); - } - - template - bool checkGlobal (char comp, const std::string& name, T value) - { - switch (MWBase::Environment::get().getWorld()->getGlobalVariableType (name)) - { - case 's': - return selectCompare (comp, MWBase::Environment::get().getWorld()->getGlobalVariable (name).mShort, value); - - case 'l': - - return selectCompare (comp, MWBase::Environment::get().getWorld()->getGlobalVariable (name).mLong, value); - - case 'f': - - return selectCompare (comp, MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat, value); - - case ' ': - - MWBase::Environment::get().getWorld()->getGlobalVariable (name); // trigger exception - break; - - default: - - throw std::runtime_error ("unsupported gobal variable type"); - } - - return false; - } - -======= ->>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 //helper function std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) { @@ -135,437 +52,7 @@ namespace namespace MWDialogue { -<<<<<<< HEAD - - - bool DialogueManager::functionFilter(const MWWorld::Ptr& actor, const ESM::DialInfo& info,bool choice) - { - bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name()); - - for (std::vector::const_iterator iter (info.mSelects.begin()); - iter != info.mSelects.end(); ++iter) - { - ESM::DialInfo::SelectStruct select = *iter; - char type = select.mSelectRule[1]; - if(type == '1') - { - char comp = select.mSelectRule[4]; - std::string name = select.mSelectRule.substr (5); - std::string function = select.mSelectRule.substr(2,2); - - int ifunction; - std::istringstream iss(function); - iss >> ifunction; - switch(ifunction) - { - case 39://PC Expelled - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 40://PC Common Disease - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 41://PC Blight Disease - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 43://PC Crime level - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 46://Same faction - { - if (isCreature) - return false; - - MWMechanics::NpcStats PCstats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - MWMechanics::NpcStats NPCstats = MWWorld::Class::get(actor).getNpcStats(actor); - int sameFaction = 0; - if(!NPCstats.getFactionRanks().empty()) - { - std::string NPCFaction = NPCstats.getFactionRanks().begin()->first; - if(PCstats.getFactionRanks().find(Misc::toLower(NPCFaction)) != PCstats.getFactionRanks().end()) sameFaction = 1; - } - if(!selectCompare(comp,sameFaction,select.mI)) return false; - } - break; - - case 48://Detected - if(!selectCompare(comp,1,select.mI)) return false; - break; - - case 49://Alarmed - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 50://choice - if(choice) - { - if(!selectCompare(comp,mChoice,select.mI)) return false; - } - break; - - case 60://PC Vampire - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 61://Level - if(!selectCompare(comp,1,select.mI)) return false; - break; - - case 62://Attacked - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 63://Talked to PC - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 64://PC Health - if(!selectCompare(comp,50,select.mI)) return false; - break; - - case 65://Creature target - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 66://Friend hit - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 67://Fight - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 68://Hello???? - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 69://Alarm - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 70://Flee - if(!selectCompare(comp,0,select.mI)) return false; - break; - - case 71://Should Attack - if(!selectCompare(comp,0,select.mI)) return false; - break; - - default: - break; - - } - } - } - - return true; - } - - bool DialogueManager::isMatching (const MWWorld::Ptr& actor, - const ESM::DialInfo::SelectStruct& select) const - { - bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name()); - - char type = select.mSelectRule[1]; - - if (type!='0') - { - char comp = select.mSelectRule[4]; - std::string name = select.mSelectRule.substr (5); - std::string function = select.mSelectRule.substr(1,2); - - switch (type) - { - case '1': // function - - return true; // Done elsewhere. - - case '2': // global - - if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || - select.mType==ESM::VT_Long) - { - if (!checkGlobal (comp, Misc::toLower (name), select.mI)) - return false; - } - else if (select.mType==ESM::VT_Float) - { - if (!checkGlobal (comp, Misc::toLower (name), select.mF)) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - - return true; - - case '3': // local - - if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || - select.mType==ESM::VT_Long) - { - if (!checkLocal (comp, Misc::toLower (name), select.mI, actor, - MWBase::Environment::get().getWorld()->getStore())) - return false; - } - else if (select.mType==ESM::VT_Float) - { - if (!checkLocal (comp, Misc::toLower (name), select.mF, actor, - MWBase::Environment::get().getWorld()->getStore())) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - - return true; - - case '4'://journal - if(select.mType==ESM::VT_Int) - { - if(!selectCompare(comp,MWBase::Environment::get().getJournal()->getJournalIndex(Misc::toLower(name)),select.mI)) return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - - return true; - - case '5'://item - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player); - - int sum = 0; - - for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (Misc::toLower(iter->getCellRef().mRefID) == Misc::toLower(name)) - sum += iter->getRefData().getCount(); - if(!selectCompare(comp,sum,select.mI)) return false; - } - - return true; - - - case '6'://dead - if(!selectCompare(comp,0,select.mI)) return false; - - case '7':// not ID - if(select.mType==ESM::VT_String ||select.mType==ESM::VT_Int)//bug in morrowind here? it's not a short, it's a string - { - int isID = int(Misc::toLower(name)==Misc::toLower(MWWorld::Class::get (actor).getId (actor))); - if (selectCompare(comp,!isID,select.mI)) return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - - return true; - - case '8':// not faction - if (isCreature) - return false; - - if(select.mType==ESM::VT_Int) - { - MWWorld::LiveCellRef* npc = actor.get(); - int isFaction = int(Misc::toLower(npc->base->mFaction) == Misc::toLower(name)); - if(selectCompare(comp,!isFaction,select.mI)) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - - return true; - - case '9':// not class - if (isCreature) - return false; - - if(select.mType==ESM::VT_Int) - { - MWWorld::LiveCellRef* npc = actor.get(); - int isClass = int(Misc::toLower(npc->base->mClass) == Misc::toLower(name)); - if(selectCompare(comp,!isClass,select.mI)) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - - return true; - - case 'A'://not Race - if (isCreature) - return false; - - if(select.mType==ESM::VT_Int) - { - MWWorld::LiveCellRef* npc = actor.get(); - int isRace = int(Misc::toLower(npc->base->mRace) == Misc::toLower(name)); - if(selectCompare(comp,!isRace,select.mI)) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - - return true; - - case 'B'://not Cell - if(select.mType==ESM::VT_Int) - { - int isCell = int(Misc::toLower(actor.getCell()->cell->mName) == Misc::toLower(name)); - if(selectCompare(comp,!isCell,select.mI)) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - return true; - - case 'C'://not local - if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || - select.mType==ESM::VT_Long) - { - if (checkLocal (comp, Misc::toLower (name), select.mI, actor, - MWBase::Environment::get().getWorld()->getStore())) - return false; - } - else if (select.mType==ESM::VT_Float) - { - if (checkLocal (comp, Misc::toLower (name), select.mF, actor, - MWBase::Environment::get().getWorld()->getStore())) - return false; - } - else - throw std::runtime_error ( - "unsupported variable type in dialogue info select"); - return true; - - - default: - - std::cout << "unchecked select: " << type << " " << comp << " " << name << std::endl; - } - } - - return true; - } - - bool DialogueManager::isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo& info) const - { - bool isCreature = (actor.getTypeName() != typeid(ESM::NPC).name()); - - // actor id - if (!info.mActor.empty()) - if (Misc::toLower (info.mActor)!=MWWorld::Class::get (actor).getId (actor)) - return false; - - //NPC race - if (!info.mRace.empty()) - { - if (isCreature) - return false; - - MWWorld::LiveCellRef *cellRef = actor.get(); - - if (!cellRef) - return false; - - if (Misc::toLower (info.mRace)!=Misc::toLower (cellRef->base->mRace)) - return false; - } - - //NPC class - if (!info.mClass.empty()) - { - if (isCreature) - return false; - - MWWorld::LiveCellRef *cellRef = actor.get(); - - if (!cellRef) - return false; - - if (Misc::toLower (info.mClass)!=Misc::toLower (cellRef->base->mClass)) - return false; - } - - //NPC faction - if (!info.mNpcFaction.empty()) - { - if (isCreature) - return false; - - //MWWorld::Class npcClass = MWWorld::Class::get(actor); - MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor); - std::map::iterator it = stats.getFactionRanks().find(Misc::toLower(info.mNpcFaction)); - if(it!=stats.getFactionRanks().end()) - { - //check rank - if(it->second < (int)info.mData.mRank) return false; - } - else - { - //not in the faction - return false; - } - } - - // TODO check player faction - if(!info.mPcFaction.empty()) - { - MWMechanics::NpcStats stats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - std::map::iterator it = stats.getFactionRanks().find(Misc::toLower(info.mPcFaction)); - if(it!=stats.getFactionRanks().end()) - { - //check rank - if(it->second < (int)info.mData.mPCrank) return false; - } - else - { - //not in the faction - return false; - } - } - - //check gender - if (!isCreature) - { - MWWorld::LiveCellRef* npc = actor.get(); - if(npc->base->mFlags & npc->base->Female) - { - if(static_cast (info.mData.mGender)==0) return false; - } - else - { - if(static_cast (info.mData.mGender)==1) return false; - } - } - - // check cell - if (!info.mCell.empty()) - if (MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell->mName != info.mCell) - return false; - - // TODO check DATAstruct - for (std::vector::const_iterator iter (info.mSelects.begin()); - iter != info.mSelects.end(); ++iter) - if (!isMatching (actor, *iter)) - return false; - - return true; - } - - DialogueManager::DialogueManager (const Compiler::Extensions& extensions) : -======= DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose) : ->>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 mCompilerContext (MWScript::CompilerContext::Type_Dialgoue), mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) , mTemporaryDispositionChange(0.f) @@ -583,11 +70,7 @@ namespace MWDialogue MWWorld::Store::iterator it = dialogs.begin(); for (; it != dialogs.end(); ++it) { -<<<<<<< HEAD - mDialogueMap[Misc::toLower(it->first)] = it->second; -======= - mDialogueMap[toLower(it->mId)] = *it; ->>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 + mDialogueMap[Misc::toLower(it->mId)] = *it; } } @@ -791,22 +274,12 @@ namespace MWDialogue { if (filter.search (*iter)) { - mActorKnownTopics.push_back (toLower (iter->mId)); + mActorKnownTopics.push_back (Misc::toLower (iter->mId)); //does the player know the topic? - if (mKnownTopics.find (toLower (iter->mId)) != mKnownTopics.end()) + if (mKnownTopics.find (Misc::toLower (iter->mId)) != mKnownTopics.end()) { -<<<<<<< HEAD - mActorKnownTopics.push_back(Misc::toLower(it->first)); - //does the player know the topic? - if(mKnownTopics.find(Misc::toLower(it->first)) != mKnownTopics.end()) - { - keywordList.push_back(it->first); - break; - } -======= keywordList.push_back (iter->mId); ->>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 } } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 98b27f774..b0bef5ea0 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -71,6 +71,7 @@ namespace MWDialogue virtual void persuade (int type); virtual int getTemporaryDispositionChange () const; virtual void applyTemporaryDispositionChange (int delta); + void toLower(std::string question); }; } From 98103e15eb55a7c63bf7796edf83e2c67d6acd0b Mon Sep 17 00:00:00 2001 From: eduard Date: Sun, 30 Dec 2012 13:46:07 +0100 Subject: [PATCH 206/916] conflict resolution --- apps/openmw/mwworld/worldimp.cpp | 21 +-------------------- components/misc/stringops.hpp | 3 --- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5e7a19caa..83c6b20e5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -235,20 +235,11 @@ namespace MWWorld } // didn't work -> now check for regions -<<<<<<< HEAD - std::string cellName2 = Misc::toLower (cellName); - - for (ESMS::RecListT::MapType::const_iterator iter (mStore.regions.list.begin()); - iter!=mStore.regions.list.end(); ++iter) - { - if (Misc::toLower (iter->second.mName)==cellName2) -======= const MWWorld::Store ®ions = mStore.get(); MWWorld::Store::iterator it = regions.begin(); for (; it != regions.end(); ++it) { if (Misc::StringUtils::ciEqual(cellName, it->mName)) ->>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 { return mStore.get().searchExtByRegion(it->mId); } @@ -625,26 +616,16 @@ namespace MWWorld CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; -<<<<<<< HEAD - if (*currCell != newCell) { - if (isPlayer) { - if (!newCell.isExterior()) { - changeToInteriorCell(Misc::toLower(newCell.cell->mName), pos); - } else { - int cellX = newCell.cell->mData.mX; - int cellY = newCell.cell->mData.mY; -======= if (*currCell != newCell) { if (isPlayer) if (!newCell.isExterior()) - changeToInteriorCell(toLower(newCell.mCell->mName), pos); + changeToInteriorCell(Misc::toLower(newCell.mCell->mName), pos); else { int cellX = newCell.mCell->getGridX(); int cellY = newCell.mCell->getGridY(); ->>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 mWorldScene->changeCell(cellX, cellY, pos, false); } else { diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index cfe7ba028..71c96b652 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -2,10 +2,7 @@ #define MISC_STRINGOPS_H #include -<<<<<<< HEAD -======= #include ->>>>>>> 92623921add0d6e16a34973dcf6f2ee1f52dbbe7 namespace Misc { From 714b1924a5758c6c7ef5c87cd25ba895e23cbcaf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Dec 2012 14:01:52 +0100 Subject: [PATCH 207/916] partial dialogue subview implementation --- apps/opencs/model/world/columns.hpp | 2 +- apps/opencs/model/world/data.cpp | 23 ++++++++++++------- apps/opencs/model/world/data.hpp | 16 +++++++++---- apps/opencs/view/world/dialoguesubview.cpp | 26 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index f58d77c90..5abf4ea8b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -1,7 +1,7 @@ #ifndef CSM_WOLRD_COLUMNS_H #define CSM_WOLRD_COLUMNS_H -#include "idcollection.hpp" +#include "columnbase.hpp" namespace CSMWorld { diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0da0cba83..a3522503e 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -10,6 +10,16 @@ #include "idtable.hpp" #include "columns.hpp" +void CSMWorld::Data::addModel (QAbstractTableModel *model, UniversalId::Type type1, + UniversalId::Type type2) +{ + mModels.push_back (model); + mModelIndex.insert (std::make_pair (type1, model)); + + if (type2!=UniversalId::Type_None) + mModelIndex.insert (std::make_pair (type2, model)); +} + CSMWorld::Data::Data() { mGlobals.addColumn (new StringIdColumn); @@ -17,16 +27,13 @@ CSMWorld::Data::Data() mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); mGlobals.addColumn (new FloatValueColumn); - mModels.insert (std::make_pair ( - UniversalId (UniversalId::Type_Globals), - new IdTable (&mGlobals) - )); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); } CSMWorld::Data::~Data() { - for (std::map::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) - delete iter->second; + for (std::vector::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) + delete *iter; } const CSMWorld::IdCollection& CSMWorld::Data::getGlobals() const @@ -41,9 +48,9 @@ CSMWorld::IdCollection& CSMWorld::Data::getGlobals() QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) { - std::map::iterator iter = mModels.find (id); + std::map::iterator iter = mModelIndex.find (id.getType()); - if (iter==mModels.end()) + if (iter==mModelIndex.end()) throw std::logic_error ("No table model available for " + id.toString()); return iter->second; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index a8a21e205..f7748cb5d 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -1,7 +1,8 @@ -#ifndef CSM_WOLRD_IDLIST_H -#define CSM_WOLRD_IDLIST_H +#ifndef CSM_WOLRD_DATA_H +#define CSM_WOLRD_DATA_H #include +#include #include @@ -15,12 +16,16 @@ namespace CSMWorld class Data { IdCollection mGlobals; - std::map mModels; + std::vector mModels; + std::map mModelIndex; // not implemented Data (const Data&); Data& operator= (const Data&); + void addModel (QAbstractTableModel *model, UniversalId::Type type1, + UniversalId::Type type2 = UniversalId::Type_None); + public: Data(); @@ -32,7 +37,10 @@ namespace CSMWorld IdCollection& getGlobals(); QAbstractTableModel *getTableModel (const UniversalId& id); - ///< If no table model is available for \æ id, an exception is thrown. + ///< If no table model is available for \a id, an exception is thrown. + /// + /// \note The returned table may either be the model for the ID itself or the model that + /// contains the record specified by the ID. void merge(); ///< Merge modified into base. diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e2d16f1e3..354223757 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -1,11 +1,37 @@ #include "dialoguesubview.hpp" +#include +#include +#include + +#include "../../model/world/columnbase.hpp" + CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete) : SubView (id) { + QWidget *widget = new QWidget (this); + setWidget (widget); + + QGridLayout *layout = new QGridLayout; + + widget->setLayout (layout); + + QAbstractTableModel *model = document.getData().getTableModel (id); + + int columns = model->columnCount(); + + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); + + if (flags & CSMWorld::ColumnBase::Flag_Dialogue) + { + layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0); + } + } } void CSVWorld::DialogueSubView::setEditLock (bool locked) From 38e7dbb970b523ea68be73aa3732f73c82e237b5 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 30 Dec 2012 16:41:25 +0100 Subject: [PATCH 208/916] mwininimporter: add more fallback values --- apps/mwiniimporter/importer.cpp | 75 +++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 0bf0ae4ec..335b7aecf 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -19,6 +19,81 @@ MwIniImporter::MwIniImporter() }; const char *fallback[] = { + // light + "LightAttenuation:UseConstant", + "LightAttenuation:ConstantValue", + "LightAttenuation:UseLinear", + "LightAttenuation:LinearMethod", + "LightAttenuation:LinearValue", + "LightAttenuation:LinearRadiusMult", + "LightAttenuation:UseQuadratic", + "LightAttenuation:QuadraticMethod", + "LightAttenuation:QuadraticValue", + "LightAttenuation:QuadraticRadiusMult", + "LightAttenuation:OutQuadInLin", + + // inventory + "Inventory:DirectionalDiffuseR", + "Inventory:DirectionalDiffuseG", + "Inventory:DirectionalDiffuseB", + "Inventory:DirectionalAmbientR", + "Inventory:DirectionalAmbientG", + "Inventory:DirectionalAmbientB", + "Inventory:DirectionalRotationX", + "Inventory:DirectionalRotationY", + "Inventory:UniformScaling", + + // map + "Map:Travel Siltstrider Red", + "Map:Travel Siltstrider Green", + "Map:Travel Siltstrider Blue", + "Map:Travel Boat Red", + "Map:Travel Boat Green", + "Map:Travel Boat Blue", + "Map:Travel Magic Red", + "Map:Travel Magic Green", + "Map:Travel Magic Blue", + "Map:Show Travel Lines", + + // water + "Water:Map Alpha", + "Water:World Alpha", + "Water:SurfaceTextureSize", + "Water:SurfaceTileCount", + "Water:SurfaceFPS", + "Water:SurfaceTexture", + "Water:SurfaceFrameCount", + "Water:TileTextureDivisor", + "Water:RippleTexture", + "Water:RippleFrameCount", + "Water:RippleLifetime", + "Water:MaxNumberRipples", + "Water:RippleScale", + "Water:RippleRotSpeed", + "Water:RippleAlphas", + "Water:PSWaterReflectTerrain", + "Water:PSWaterReflectUpdate", + "Water:NearWaterRadius", + "Water:NearWaterPoints", + "Water:NearWaterUnderwaterFreq", + "Water:NearWaterUnderwaterVolume", + "Water:NearWaterIndoorTolerance", + "Water:NearWaterOutdoorTolerance", + "Water:NearWaterIndoorID", + "Water:NearWaterOutdoorID", + "Water:UnderwaterSunriseFog", + "Water:UnderwaterDayFog", + "Water:UnderwaterSunsetFog", + "Water:UnderwaterNightFog", + "Water:UnderwaterIndoorFog", + "Water:UnderwaterColor", + "Water:UnderwaterColorWeight", + + // pixelwater + "PixelWater:SurfaceFPS", + "PixelWater:TileCount", + "PixelWater:Resolution", + /* "Fonts:Font 0", "Fonts:Font 1", From cb71efc4279146467e53098748d87e7f9a649325 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 30 Dec 2012 16:44:52 +0100 Subject: [PATCH 209/916] mwiniimporter: clean up --- apps/mwiniimporter/importer.cpp | 643 +++++++++++++++----------------- 1 file changed, 306 insertions(+), 337 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 335b7aecf..dda8fd8ba 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -94,13 +94,12 @@ MwIniImporter::MwIniImporter() "PixelWater:TileCount", "PixelWater:Resolution", - /* + // fonts "Fonts:Font 0", "Fonts:Font 1", "Fonts:Font 2", - */ - /* + // UI colors "FontColor:color_normal", "FontColor:color_normal_over", "FontColor:color_normal_pressed", @@ -146,18 +145,15 @@ MwIniImporter::MwIniImporter() "FontColor:color_positive", "FontColor:color_negative", "FontColor:color_count", - */ - /* + // cursors "Cursors:Cursor 0", "Cursors:Cursor 1", "Cursors:Cursor 2", "Cursors:Cursor 3", "Cursors:Cursor 4", - */ // level up messages - // not used for now "Level Up:Level2", "Level Up:Level3", "Level Up:Level4", @@ -180,7 +176,6 @@ MwIniImporter::MwIniImporter() "Level Up:Default", // character creation multiple choice test - // hardcoded in mwgui/charactercreation.cpp "Question 1:Question", "Question 1:AnswerOne", "Question 1:AnswerTwo", @@ -233,7 +228,6 @@ MwIniImporter::MwIniImporter() "Question 10:Sound", // blood textures and models - // not used for now "Blood:Model 0", "Blood:Model 1", "Blood:Model 2", @@ -245,7 +239,6 @@ MwIniImporter::MwIniImporter() "Blood:Texture Name 2", // movies - // not used for now "Movies:Company Logo", "Movies:Morrowind Logo", "Movies:New Game", @@ -253,10 +246,7 @@ MwIniImporter::MwIniImporter() "Movies:Options Menu", // weather related values - // hardcoded in mwworld/wheather.cpp - // Some are easy to replace, others are used as magic number - // globals "Weather Thunderstorm:Thunder Sound ID 0", "Weather Thunderstorm:Thunder Sound ID 1", "Weather Thunderstorm:Thunder Sound ID 2", @@ -268,296 +258,7 @@ MwIniImporter::MwIniImporter() "Weather:Hours Between Weather Changes", // AKA weather update time "Weather Thunderstorm:Thunder Frequency", "Weather Thunderstorm:Thunder Threshold", - // thunder sound delay? - "Weather Clear:Cloud Texture", - "Weather Clear:Clouds Maximum Percent", - "Weather Clear:Transition Delta", - "Weather Clear:Sky Sunrise Color", - "Weather Clear:Sky Day Color", - "Weather Clear:Sky Sunset Color", - "Weather Clear:Sky Night Color", - "Weather Clear:Fog Sunrise Color", - "Weather Clear:Fog Day Color", - "Weather Clear:Fog Sunset Color", - "Weather Clear:Fog Night Color", - "Weather Clear:Ambient Sunrise Color", - "Weather Clear:Ambient Day Color", - "Weather Clear:Ambient Sunset Color", - "Weather Clear:Ambient Night Color", - "Weather Clear:Sun Sunrise Color", - "Weather Clear:Sun Day Color", - "Weather Clear:Sun Sunset Color", - "Weather Clear:Sun Night Color", - "Weather Clear:Sun Disc Sunset Color", - "Weather Clear:Land Fog Day Depth", - "Weather Clear:Land Fog Night Depth", - "Weather Clear:Wind Speed", - "Weather Clear:Cloud Speed", - "Weather Clear:Glare View", - - "Weather Cloudy:Cloud Texture", - "Weather Cloudy:Clouds Maximum Percent", - "Weather Cloudy:Transition Delta", - "Weather Cloudy:Sky Sunrise Color", - "Weather Cloudy:Sky Day Color", - "Weather Cloudy:Sky Sunset Color", - "Weather Cloudy:Sky Night Color", - "Weather Cloudy:Fog Sunrise Color", - "Weather Cloudy:Fog Day Color", - "Weather Cloudy:Fog Sunset Color", - "Weather Cloudy:Fog Night Color", - "Weather Cloudy:Ambient Sunrise Color", - "Weather Cloudy:Ambient Day Color", - "Weather Cloudy:Ambient Sunset Color", - "Weather Cloudy:Ambient Night Color", - "Weather Cloudy:Sun Sunrise Color", - "Weather Cloudy:Sun Day Color", - "Weather Cloudy:Sun Sunset Color", - "Weather Cloudy:Sun Night Color", - "Weather Cloudy:Sun Disc Sunset Color", - "Weather Cloudy:Land Fog Day Depth", - "Weather Cloudy:Land Fog Night Depth", - "Weather Cloudy:Wind Speed", - "Weather Cloudy:Cloud Speed", - "Weather Cloudy:Glare View", - - "Weather Foggy:Cloud Texture", - "Weather Foggy:Clouds Maximum Percent", - "Weather Foggy:Transition Delta", - "Weather Foggy:Sky Sunrise Color", - "Weather Foggy:Sky Day Color", - "Weather Foggy:Sky Sunset Color", - "Weather Foggy:Sky Night Color", - "Weather Foggy:Fog Sunrise Color", - "Weather Foggy:Fog Day Color", - "Weather Foggy:Fog Sunset Color", - "Weather Foggy:Fog Night Color", - "Weather Foggy:Ambient Sunrise Color", - "Weather Foggy:Ambient Day Color", - "Weather Foggy:Ambient Sunset Color", - "Weather Foggy:Ambient Night Color", - "Weather Foggy:Sun Sunrise Color", - "Weather Foggy:Sun Day Color", - "Weather Foggy:Sun Sunset Color", - "Weather Foggy:Sun Night Color", - "Weather Foggy:Sun Disc Sunset Color", - "Weather Foggy:Land Fog Day Depth", - "Weather Foggy:Land Fog Night Depth", - "Weather Foggy:Wind Speed", - "Weather Foggy:Cloud Speed", - "Weather Foggy:Glare View", - - "Weather Thunderstorm:Cloud Texture", - "Weather Thunderstorm:Clouds Maximum Percent", - "Weather Thunderstorm:Transition Delta", - "Weather Thunderstorm:Sky Sunrise Color", - "Weather Thunderstorm:Sky Day Color", - "Weather Thunderstorm:Sky Sunset Color", - "Weather Thunderstorm:Sky Night Color", - "Weather Thunderstorm:Fog Sunrise Color", - "Weather Thunderstorm:Fog Day Color", - "Weather Thunderstorm:Fog Sunset Color", - "Weather Thunderstorm:Fog Night Color", - "Weather Thunderstorm:Ambient Sunrise Color", - "Weather Thunderstorm:Ambient Day Color", - "Weather Thunderstorm:Ambient Sunset Color", - "Weather Thunderstorm:Ambient Night Color", - "Weather Thunderstorm:Sun Sunrise Color", - "Weather Thunderstorm:Sun Day Color", - "Weather Thunderstorm:Sun Sunset Color", - "Weather Thunderstorm:Sun Night Color", - "Weather Thunderstorm:Sun Disc Sunset Color", - "Weather Thunderstorm:Land Fog Day Depth", - "Weather Thunderstorm:Land Fog Night Depth", - "Weather Thunderstorm:Wind Speed", - "Weather Thunderstorm:Cloud Speed", - "Weather Thunderstorm:Glare View", - "Weather Thunderstorm:Rain Loop Sound ID", - - "Weather Rain:Cloud Texture", - "Weather Rain:Clouds Maximum Percent", - "Weather Rain:Transition Delta", - "Weather Rain:Sky Sunrise Color", - "Weather Rain:Sky Day Color", - "Weather Rain:Sky Sunset Color", - "Weather Rain:Sky Night Color", - "Weather Rain:Fog Sunrise Color", - "Weather Rain:Fog Day Color", - "Weather Rain:Fog Sunset Color", - "Weather Rain:Fog Night Color", - "Weather Rain:Ambient Sunrise Color", - "Weather Rain:Ambient Day Color", - "Weather Rain:Ambient Sunset Color", - "Weather Rain:Ambient Night Color", - "Weather Rain:Sun Sunrise Color", - "Weather Rain:Sun Day Color", - "Weather Rain:Sun Sunset Color", - "Weather Rain:Sun Night Color", - "Weather Rain:Sun Disc Sunset Color", - "Weather Rain:Land Fog Day Depth", - "Weather Rain:Land Fog Night Depth", - "Weather Rain:Wind Speed", - "Weather Rain:Cloud Speed", - "Weather Rain:Glare View", - "Weather Rain:Rain Loop Sound ID", - - "Weather Overcast:Cloud Texture", - "Weather Overcast:Clouds Maximum Percent", - "Weather Overcast:Transition Delta", - "Weather Overcast:Sky Sunrise Color", - "Weather Overcast:Sky Day Color", - "Weather Overcast:Sky Sunset Color", - "Weather Overcast:Sky Night Color", - "Weather Overcast:Fog Sunrise Color", - "Weather Overcast:Fog Day Color", - "Weather Overcast:Fog Sunset Color", - "Weather Overcast:Fog Night Color", - "Weather Overcast:Ambient Sunrise Color", - "Weather Overcast:Ambient Day Color", - "Weather Overcast:Ambient Sunset Color", - "Weather Overcast:Ambient Night Color", - "Weather Overcast:Sun Sunrise Color", - "Weather Overcast:Sun Day Color", - "Weather Overcast:Sun Sunset Color", - "Weather Overcast:Sun Night Color", - "Weather Overcast:Sun Disc Sunset Color", - "Weather Overcast:Land Fog Day Depth", - "Weather Overcast:Land Fog Night Depth", - "Weather Overcast:Wind Speed", - "Weather Overcast:Cloud Speed", - "Weather Overcast:Glare View", - - "Weather Ashstorm:Cloud Texture", - "Weather Ashstorm:Clouds Maximum Percent", - "Weather Ashstorm:Transition Delta", - "Weather Ashstorm:Sky Sunrise Color", - "Weather Ashstorm:Sky Day Color", - "Weather Ashstorm:Sky Sunset Color", - "Weather Ashstorm:Sky Night Color", - "Weather Ashstorm:Fog Sunrise Color", - "Weather Ashstorm:Fog Day Color", - "Weather Ashstorm:Fog Sunset Color", - "Weather Ashstorm:Fog Night Color", - "Weather Ashstorm:Ambient Sunrise Color", - "Weather Ashstorm:Ambient Day Color", - "Weather Ashstorm:Ambient Sunset Color", - "Weather Ashstorm:Ambient Night Color", - "Weather Ashstorm:Sun Sunrise Color", - "Weather Ashstorm:Sun Day Color", - "Weather Ashstorm:Sun Sunset Color", - "Weather Ashstorm:Sun Night Color", - "Weather Ashstorm:Sun Disc Sunset Color", - "Weather Ashstorm:Land Fog Day Depth", - "Weather Ashstorm:Land Fog Night Depth", - "Weather Ashstorm:Wind Speed", - "Weather Ashstorm:Cloud Speed", - "Weather Ashstorm:Glare View", - "Weather Ashstorm:Ambient Loop Sound ID", - - "Weather Blight:Cloud Texture", - "Weather Blight:Clouds Maximum Percent", - "Weather Blight:Transition Delta", - "Weather Blight:Sky Sunrise Color", - "Weather Blight:Sky Day Color", - "Weather Blight:Sky Sunset Color", - "Weather Blight:Sky Night Color", - "Weather Blight:Fog Sunrise Color", - "Weather Blight:Fog Day Color", - "Weather Blight:Fog Sunset Color", - "Weather Blight:Fog Night Color", - "Weather Blight:Ambient Sunrise Color", - "Weather Blight:Ambient Day Color", - "Weather Blight:Ambient Sunset Color", - "Weather Blight:Ambient Night Color", - "Weather Blight:Sun Sunrise Color", - "Weather Blight:Sun Day Color", - "Weather Blight:Sun Sunset Color", - "Weather Blight:Sun Night Color", - "Weather Blight:Sun Disc Sunset Color", - "Weather Blight:Land Fog Day Depth", - "Weather Blight:Land Fog Night Depth", - "Weather Blight:Wind Speed", - "Weather Blight:Cloud Speed", - "Weather Blight:Glare View", - "Weather Blight:Ambient Loop Sound ID", - - // not used for now (todo) - "Weather Blight:Disease Chance", - - // for Bloodmoon - "Weather Snow:Cloud Texture", - "Weather Snow:Clouds Maximum Percent", - "Weather Snow:Transition Delta", - "Weather Snow:Sky Sunrise Color", - "Weather Snow:Sky Day Color", - "Weather Snow:Sky Sunset Color", - "Weather Snow:Sky Night Color", - "Weather Snow:Fog Sunrise Color", - "Weather Snow:Fog Day Color", - "Weather Snow:Fog Sunset Color", - "Weather Snow:Fog Night Color", - "Weather Snow:Ambient Sunrise Color", - "Weather Snow:Ambient Day Color", - "Weather Snow:Ambient Sunset Color", - "Weather Snow:Ambient Night Color", - "Weather Snow:Sun Sunrise Color", - "Weather Snow:Sun Day Color", - "Weather Snow:Sun Sunset Color", - "Weather Snow:Sun Night Color", - "Weather Snow:Sun Disc Sunset Color", - "Weather Snow:Land Fog Day Depth", - "Weather Snow:Land Fog Night Depth", - "Weather Snow:Wind Speed", - "Weather Snow:Cloud Speed", - "Weather Snow:Glare View", - - // for Bloodmoon - "Weather Blizzard:Cloud Texture", - "Weather Blizzard:Clouds Maximum Percent", - "Weather Blizzard:Transition Delta", - "Weather Blizzard:Sky Sunrise Color", - "Weather Blizzard:Sky Day Color", - "Weather Blizzard:Sky Sunset Color", - "Weather Blizzard:Sky Night Color", - "Weather Blizzard:Fog Sunrise Color", - "Weather Blizzard:Fog Day Color", - "Weather Blizzard:Fog Sunset Color", - "Weather Blizzard:Fog Night Color", - "Weather Blizzard:Ambient Sunrise Color", - "Weather Blizzard:Ambient Day Color", - "Weather Blizzard:Ambient Sunset Color", - "Weather Blizzard:Ambient Night Color", - "Weather Blizzard:Sun Sunrise Color", - "Weather Blizzard:Sun Day Color", - "Weather Blizzard:Sun Sunset Color", - "Weather Blizzard:Sun Night Color", - "Weather Blizzard:Sun Disc Sunset Color", - "Weather Blizzard:Land Fog Day Depth", - "Weather Blizzard:Land Fog Night Depth", - "Weather Blizzard:Wind Speed", - "Weather Blizzard:Cloud Speed", - "Weather Blizzard:Glare View", - "Weather Blizzard:Ambient Loop Sound ID", - - // not used - "Weather Clear:Ambient Loop Sound ID", - "Weather Cloudy:Ambient Loop Sound ID", - "Weather Foggy:Ambient Loop Sound ID", - "Weather Overcast:Ambient Loop Sound ID", - "Weather Snow:Ambient Loop Sound ID", - // - "Weather Ashstorm:Storm Threshold", - "Weather Blight:Storm Threshold", - "Weather Snow:Snow Threshold", - "Weather Blizzard:Storm Threshold", - // - "Weather Snow:Snow Diameter", - "Weather Snow:Snow Height Min", - "Weather Snow:Snow Height Max", - "Weather Snow:Snow Entrance Speed", - "Weather Snow:Max Snowflakes", - // "Weather:EnvReduceColor", "Weather:LerpCloseColor", "Weather:BumpFadeColor", @@ -602,16 +303,114 @@ MwIniImporter::MwIniImporter() "Weather:Snow Gravity Scale", "Weather:Snow High Kill", "Weather:Snow Low Kill", - // - "Weather Rain:Using Precip", - "Weather Rain:Rain Diameter", - "Weather Rain:Rain Height Min", - "Weather Rain:Rain Height Max", - "Weather Rain:Rain Threshold", - "Weather Rain:Rain Entrance Speed", - "Weather Rain:Ambient Loop Sound ID", - "Weather Rain:Max Raindrops", - // + + "Weather Clear:Cloud Texture", + "Weather Clear:Clouds Maximum Percent", + "Weather Clear:Transition Delta", + "Weather Clear:Sky Sunrise Color", + "Weather Clear:Sky Day Color", + "Weather Clear:Sky Sunset Color", + "Weather Clear:Sky Night Color", + "Weather Clear:Fog Sunrise Color", + "Weather Clear:Fog Day Color", + "Weather Clear:Fog Sunset Color", + "Weather Clear:Fog Night Color", + "Weather Clear:Ambient Sunrise Color", + "Weather Clear:Ambient Day Color", + "Weather Clear:Ambient Sunset Color", + "Weather Clear:Ambient Night Color", + "Weather Clear:Sun Sunrise Color", + "Weather Clear:Sun Day Color", + "Weather Clear:Sun Sunset Color", + "Weather Clear:Sun Night Color", + "Weather Clear:Sun Disc Sunset Color", + "Weather Clear:Land Fog Day Depth", + "Weather Clear:Land Fog Night Depth", + "Weather Clear:Wind Speed", + "Weather Clear:Cloud Speed", + "Weather Clear:Glare View", + "Weather Clear:Ambient Loop Sound ID", + + "Weather Cloudy:Cloud Texture", + "Weather Cloudy:Clouds Maximum Percent", + "Weather Cloudy:Transition Delta", + "Weather Cloudy:Sky Sunrise Color", + "Weather Cloudy:Sky Day Color", + "Weather Cloudy:Sky Sunset Color", + "Weather Cloudy:Sky Night Color", + "Weather Cloudy:Fog Sunrise Color", + "Weather Cloudy:Fog Day Color", + "Weather Cloudy:Fog Sunset Color", + "Weather Cloudy:Fog Night Color", + "Weather Cloudy:Ambient Sunrise Color", + "Weather Cloudy:Ambient Day Color", + "Weather Cloudy:Ambient Sunset Color", + "Weather Cloudy:Ambient Night Color", + "Weather Cloudy:Sun Sunrise Color", + "Weather Cloudy:Sun Day Color", + "Weather Cloudy:Sun Sunset Color", + "Weather Cloudy:Sun Night Color", + "Weather Cloudy:Sun Disc Sunset Color", + "Weather Cloudy:Land Fog Day Depth", + "Weather Cloudy:Land Fog Night Depth", + "Weather Cloudy:Wind Speed", + "Weather Cloudy:Cloud Speed", + "Weather Cloudy:Glare View", + "Weather Cloudy:Ambient Loop Sound ID", + + "Weather Foggy:Cloud Texture", + "Weather Foggy:Clouds Maximum Percent", + "Weather Foggy:Transition Delta", + "Weather Foggy:Sky Sunrise Color", + "Weather Foggy:Sky Day Color", + "Weather Foggy:Sky Sunset Color", + "Weather Foggy:Sky Night Color", + "Weather Foggy:Fog Sunrise Color", + "Weather Foggy:Fog Day Color", + "Weather Foggy:Fog Sunset Color", + "Weather Foggy:Fog Night Color", + "Weather Foggy:Ambient Sunrise Color", + "Weather Foggy:Ambient Day Color", + "Weather Foggy:Ambient Sunset Color", + "Weather Foggy:Ambient Night Color", + "Weather Foggy:Sun Sunrise Color", + "Weather Foggy:Sun Day Color", + "Weather Foggy:Sun Sunset Color", + "Weather Foggy:Sun Night Color", + "Weather Foggy:Sun Disc Sunset Color", + "Weather Foggy:Land Fog Day Depth", + "Weather Foggy:Land Fog Night Depth", + "Weather Foggy:Wind Speed", + "Weather Foggy:Cloud Speed", + "Weather Foggy:Glare View", + "Weather Foggy:Ambient Loop Sound ID", + + "Weather Thunderstorm:Cloud Texture", + "Weather Thunderstorm:Clouds Maximum Percent", + "Weather Thunderstorm:Transition Delta", + "Weather Thunderstorm:Sky Sunrise Color", + "Weather Thunderstorm:Sky Day Color", + "Weather Thunderstorm:Sky Sunset Color", + "Weather Thunderstorm:Sky Night Color", + "Weather Thunderstorm:Fog Sunrise Color", + "Weather Thunderstorm:Fog Day Color", + "Weather Thunderstorm:Fog Sunset Color", + "Weather Thunderstorm:Fog Night Color", + "Weather Thunderstorm:Ambient Sunrise Color", + "Weather Thunderstorm:Ambient Day Color", + "Weather Thunderstorm:Ambient Sunset Color", + "Weather Thunderstorm:Ambient Night Color", + "Weather Thunderstorm:Sun Sunrise Color", + "Weather Thunderstorm:Sun Day Color", + "Weather Thunderstorm:Sun Sunset Color", + "Weather Thunderstorm:Sun Night Color", + "Weather Thunderstorm:Sun Disc Sunset Color", + "Weather Thunderstorm:Land Fog Day Depth", + "Weather Thunderstorm:Land Fog Night Depth", + "Weather Thunderstorm:Wind Speed", + "Weather Thunderstorm:Cloud Speed", + "Weather Thunderstorm:Glare View", + "Weather Thunderstorm:Rain Loop Sound ID", "Weather Thunderstorm:Using Precip", "Weather Thunderstorm:Rain Diameter", "Weather Thunderstorm:Rain Height Min", @@ -622,42 +421,212 @@ MwIniImporter::MwIniImporter() "Weather Thunderstorm:Ambient Loop Sound ID", "Weather Thunderstorm:Flash Decrement", + "Weather Rain:Cloud Texture", + "Weather Rain:Clouds Maximum Percent", + "Weather Rain:Transition Delta", + "Weather Rain:Sky Sunrise Color", + "Weather Rain:Sky Day Color", + "Weather Rain:Sky Sunset Color", + "Weather Rain:Sky Night Color", + "Weather Rain:Fog Sunrise Color", + "Weather Rain:Fog Day Color", + "Weather Rain:Fog Sunset Color", + "Weather Rain:Fog Night Color", + "Weather Rain:Ambient Sunrise Color", + "Weather Rain:Ambient Day Color", + "Weather Rain:Ambient Sunset Color", + "Weather Rain:Ambient Night Color", + "Weather Rain:Sun Sunrise Color", + "Weather Rain:Sun Day Color", + "Weather Rain:Sun Sunset Color", + "Weather Rain:Sun Night Color", + "Weather Rain:Sun Disc Sunset Color", + "Weather Rain:Land Fog Day Depth", + "Weather Rain:Land Fog Night Depth", + "Weather Rain:Wind Speed", + "Weather Rain:Cloud Speed", + "Weather Rain:Glare View", + "Weather Rain:Rain Loop Sound ID", + "Weather Rain:Using Precip", + "Weather Rain:Rain Diameter", + "Weather Rain:Rain Height Min", + "Weather Rain:Rain Height Max", + "Weather Rain:Rain Threshold", + "Weather Rain:Rain Entrance Speed", + "Weather Rain:Ambient Loop Sound ID", + "Weather Rain:Max Raindrops", + + "Weather Overcast:Cloud Texture", + "Weather Overcast:Clouds Maximum Percent", + "Weather Overcast:Transition Delta", + "Weather Overcast:Sky Sunrise Color", + "Weather Overcast:Sky Day Color", + "Weather Overcast:Sky Sunset Color", + "Weather Overcast:Sky Night Color", + "Weather Overcast:Fog Sunrise Color", + "Weather Overcast:Fog Day Color", + "Weather Overcast:Fog Sunset Color", + "Weather Overcast:Fog Night Color", + "Weather Overcast:Ambient Sunrise Color", + "Weather Overcast:Ambient Day Color", + "Weather Overcast:Ambient Sunset Color", + "Weather Overcast:Ambient Night Color", + "Weather Overcast:Sun Sunrise Color", + "Weather Overcast:Sun Day Color", + "Weather Overcast:Sun Sunset Color", + "Weather Overcast:Sun Night Color", + "Weather Overcast:Sun Disc Sunset Color", + "Weather Overcast:Land Fog Day Depth", + "Weather Overcast:Land Fog Night Depth", + "Weather Overcast:Wind Speed", + "Weather Overcast:Cloud Speed", + "Weather Overcast:Glare View", + "Weather Overcast:Ambient Loop Sound ID", + + "Weather Ashstorm:Cloud Texture", + "Weather Ashstorm:Clouds Maximum Percent", + "Weather Ashstorm:Transition Delta", + "Weather Ashstorm:Sky Sunrise Color", + "Weather Ashstorm:Sky Day Color", + "Weather Ashstorm:Sky Sunset Color", + "Weather Ashstorm:Sky Night Color", + "Weather Ashstorm:Fog Sunrise Color", + "Weather Ashstorm:Fog Day Color", + "Weather Ashstorm:Fog Sunset Color", + "Weather Ashstorm:Fog Night Color", + "Weather Ashstorm:Ambient Sunrise Color", + "Weather Ashstorm:Ambient Day Color", + "Weather Ashstorm:Ambient Sunset Color", + "Weather Ashstorm:Ambient Night Color", + "Weather Ashstorm:Sun Sunrise Color", + "Weather Ashstorm:Sun Day Color", + "Weather Ashstorm:Sun Sunset Color", + "Weather Ashstorm:Sun Night Color", + "Weather Ashstorm:Sun Disc Sunset Color", + "Weather Ashstorm:Land Fog Day Depth", + "Weather Ashstorm:Land Fog Night Depth", + "Weather Ashstorm:Wind Speed", + "Weather Ashstorm:Cloud Speed", + "Weather Ashstorm:Glare View", + "Weather Ashstorm:Ambient Loop Sound ID", + "Weather Ashstorm:Storm Threshold", + + "Weather Blight:Cloud Texture", + "Weather Blight:Clouds Maximum Percent", + "Weather Blight:Transition Delta", + "Weather Blight:Sky Sunrise Color", + "Weather Blight:Sky Day Color", + "Weather Blight:Sky Sunset Color", + "Weather Blight:Sky Night Color", + "Weather Blight:Fog Sunrise Color", + "Weather Blight:Fog Day Color", + "Weather Blight:Fog Sunset Color", + "Weather Blight:Fog Night Color", + "Weather Blight:Ambient Sunrise Color", + "Weather Blight:Ambient Day Color", + "Weather Blight:Ambient Sunset Color", + "Weather Blight:Ambient Night Color", + "Weather Blight:Sun Sunrise Color", + "Weather Blight:Sun Day Color", + "Weather Blight:Sun Sunset Color", + "Weather Blight:Sun Night Color", + "Weather Blight:Sun Disc Sunset Color", + "Weather Blight:Land Fog Day Depth", + "Weather Blight:Land Fog Night Depth", + "Weather Blight:Wind Speed", + "Weather Blight:Cloud Speed", + "Weather Blight:Glare View", + "Weather Blight:Ambient Loop Sound ID", + "Weather Blight:Storm Threshold", + "Weather Blight:Disease Chance", + + // for Bloodmoon + "Weather Snow:Cloud Texture", + "Weather Snow:Clouds Maximum Percent", + "Weather Snow:Transition Delta", + "Weather Snow:Sky Sunrise Color", + "Weather Snow:Sky Day Color", + "Weather Snow:Sky Sunset Color", + "Weather Snow:Sky Night Color", + "Weather Snow:Fog Sunrise Color", + "Weather Snow:Fog Day Color", + "Weather Snow:Fog Sunset Color", + "Weather Snow:Fog Night Color", + "Weather Snow:Ambient Sunrise Color", + "Weather Snow:Ambient Day Color", + "Weather Snow:Ambient Sunset Color", + "Weather Snow:Ambient Night Color", + "Weather Snow:Sun Sunrise Color", + "Weather Snow:Sun Day Color", + "Weather Snow:Sun Sunset Color", + "Weather Snow:Sun Night Color", + "Weather Snow:Sun Disc Sunset Color", + "Weather Snow:Land Fog Day Depth", + "Weather Snow:Land Fog Night Depth", + "Weather Snow:Wind Speed", + "Weather Snow:Cloud Speed", + "Weather Snow:Glare View", + "Weather Snow:Snow Diameter", + "Weather Snow:Snow Height Min", + "Weather Snow:Snow Height Max", + "Weather Snow:Snow Entrance Speed", + "Weather Snow:Max Snowflakes", + "Weather Snow:Ambient Loop Sound ID", + "Weather Snow:Snow Threshold", + + // for Bloodmoon + "Weather Blizzard:Cloud Texture", + "Weather Blizzard:Clouds Maximum Percent", + "Weather Blizzard:Transition Delta", + "Weather Blizzard:Sky Sunrise Color", + "Weather Blizzard:Sky Day Color", + "Weather Blizzard:Sky Sunset Color", + "Weather Blizzard:Sky Night Color", + "Weather Blizzard:Fog Sunrise Color", + "Weather Blizzard:Fog Day Color", + "Weather Blizzard:Fog Sunset Color", + "Weather Blizzard:Fog Night Color", + "Weather Blizzard:Ambient Sunrise Color", + "Weather Blizzard:Ambient Day Color", + "Weather Blizzard:Ambient Sunset Color", + "Weather Blizzard:Ambient Night Color", + "Weather Blizzard:Sun Sunrise Color", + "Weather Blizzard:Sun Day Color", + "Weather Blizzard:Sun Sunset Color", + "Weather Blizzard:Sun Night Color", + "Weather Blizzard:Sun Disc Sunset Color", + "Weather Blizzard:Land Fog Day Depth", + "Weather Blizzard:Land Fog Night Depth", + "Weather Blizzard:Wind Speed", + "Weather Blizzard:Cloud Speed", + "Weather Blizzard:Glare View", + "Weather Blizzard:Ambient Loop Sound ID", + "Weather Blizzard:Storm Threshold", + // moons - - // these are hardcoded in mwworld/weather.cpp - // l.642..665 (masser_angle_fade) - "Moons:Secunda Fade Start Angle", // = 50 - "Moons:Secunda Fade End Angle", // = 40 - "Moons:Masser Fade Start Angle", // = 50 - "Moons:Masser Fade End Angle", // = 30 - - // hardcoded in weather.cpp l.635 to 641 (hour_fade) - "Moons:Secunda Fade In Start", // = 14 - "Moons:Secunda Fade In Finish", // = 15 - "Moons:Secunda Fade Out Start", // = 7 - "Moons:Secunda Fade Out Finish", // = 10 - - // same values as Secunda - "Moons:Masser Fade In Start", - "Moons:Masser Fade In Finish", - "Moons:Masser Fade Out Start", - "Moons:Masser Fade Out Finish", - - // color code hardcoded in mwrender/sky.cpp (l.417, mMoonRed) - // as float values (divided by 255) - "Moons:Script Color", - - // not used "Moons:Secunda Size", "Moons:Secunda Axis Offset", "Moons:Secunda Speed", "Moons:Secunda Daily Increment", "Moons:Secunda Moon Shadow Early Fade Angle", + "Moons:Secunda Fade Start Angle", + "Moons:Secunda Fade End Angle", + "Moons:Secunda Fade In Start", + "Moons:Secunda Fade In Finish", + "Moons:Secunda Fade Out Start", + "Moons:Secunda Fade Out Finish", "Moons:Masser Size", "Moons:Masser Axis Offset", "Moons:Masser Speed", "Moons:Masser Daily Increment", "Moons:Masser Moon Shadow Early Fade Angle", + "Moons:Masser Fade Start Angle", + "Moons:Masser Fade End Angle", + "Moons:Masser Fade In Start", + "Moons:Masser Fade In Finish", + "Moons:Masser Fade Out Start", + "Moons:Masser Fade Out Finish", + "Moons:Script Color", 0 }; From f56182cac28631740e139b963ebcf3545d157529 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Dec 2012 17:06:17 +0100 Subject: [PATCH 210/916] fix journal window not rendering any text --- apps/openmw/mwgui/journalwindow.cpp | 13 ++++--------- apps/openmw/mwgui/journalwindow.hpp | 4 +--- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 9d5d236be..bbd3d4d28 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -84,9 +84,9 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) : WindowBase("openmw_journal.layout", parWindowManager) , mLastPos(0) - , mVisible(false) , mPageNumber(0) { + mMainWidget->setVisible(false); //setCoord(0,0,498, 342); center(); @@ -115,20 +115,15 @@ MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) //displayLeftText(list.front()); } -void MWGui::JournalWindow::setVisible(bool visible) +void MWGui::JournalWindow::close() { - if (mVisible && !visible) - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - mVisible = visible; - - mMainWidget->setVisible(visible); + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); } void MWGui::JournalWindow::open() { mPageNumber = 0; - std::string journalOpenSound = "book open"; - MWBase::Environment::get().getSoundManager()->playSound (journalOpenSound, 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) { book journal; diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index a62e48803..3317880cd 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -15,8 +15,7 @@ namespace MWGui public: JournalWindow(MWBase::WindowManager& parWindowManager); virtual void open(); - - virtual void setVisible(bool visible); // only used to play close sound + virtual void close(); private: void displayLeftText(std::string text); @@ -41,7 +40,6 @@ namespace MWGui std::vector mLeftPages; std::vector mRightPages; int mPageNumber; //store the number of the current left page - bool mVisible; }; } From 69d9d22579c4ddf2b4b5fffb7355bd0b5413f0cb Mon Sep 17 00:00:00 2001 From: eduard Date: Sun, 30 Dec 2012 19:56:38 +0100 Subject: [PATCH 211/916] comparestring --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 16 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwscript/containerextensions.cpp | 15 +- apps/openmw/mwworld/worldimp.cpp | 2 +- components/esm_store/reclists.hpp | 674 ------------------ components/misc/stringops.cpp | 26 - components/misc/stringops.hpp | 6 - 7 files changed, 18 insertions(+), 723 deletions(-) delete mode 100644 components/esm_store/reclists.hpp diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 8e74894b9..80999c5ff 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -45,8 +45,8 @@ namespace //helper function std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) - { - return Misc::toLower(str).find(Misc::toLower(substr),pos); + { + return Misc::StringUtils::toLower(const_cast(str)).find(Misc::StringUtils::toLower(const_cast(substr)).c_str(),pos); } } @@ -70,13 +70,13 @@ namespace MWDialogue MWWorld::Store::iterator it = dialogs.begin(); for (; it != dialogs.end(); ++it) { - mDialogueMap[Misc::toLower(it->mId)] = *it; + mDialogueMap[Misc::StringUtils::toLower(const_cast(it->mId))] = *it; } } void DialogueManager::addTopic (const std::string& topic) { - mKnownTopics[Misc::toLower(topic)] = true; + mKnownTopics[Misc::StringUtils::toLower(const_cast(topic))] = true; } void DialogueManager::parseText (const std::string& text) @@ -274,10 +274,10 @@ namespace MWDialogue { if (filter.search (*iter)) { - mActorKnownTopics.push_back (Misc::toLower (iter->mId)); + mActorKnownTopics.push_back ( Misc::StringUtils::toLower(const_cast(iter->mId))); //does the player know the topic? - if (mKnownTopics.find (Misc::toLower (iter->mId)) != mKnownTopics.end()) + if (mKnownTopics.find ( Misc::StringUtils::toLower(const_cast(iter->mId))) != mKnownTopics.end()) { keywordList.push_back (iter->mId); } @@ -335,7 +335,7 @@ namespace MWDialogue win->setServices (windowServices); // sort again, because the previous sort was case-sensitive - keywordList.sort(Misc::stringCompareNoCase); + keywordList.sort(Misc::StringUtils::ciEqual); win->setKeywords(keywordList); mChoice = choice; @@ -415,7 +415,7 @@ namespace MWDialogue { MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->askQuestion(question); - mChoiceMap[Misc::toLower(question)] = choice; + mChoiceMap[Misc::StringUtils::toLower(const_cast(question))] = choice; mIsInChoice = true; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1ac5b2fc6..dd75b8216 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -271,7 +271,7 @@ namespace MWGui for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { - if (Misc::toLower(it->getCellRef().mRefID) == "gold_001") + if (Misc::StringUtils::toLower(it->getCellRef().mRefID) == "gold_001") return it->getRefData().getCount(); } return 0; diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 114704388..2cdad2a90 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -72,7 +72,7 @@ namespace MWScript Interpreter::Type_Integer sum = 0; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (Misc::toLower(iter->getCellRef().mRefID) == Misc::toLower(item)) + if (Misc::StringUtils::toLower(iter->getCellRef().mRefID) == Misc::StringUtils::toLower(item)) sum += iter->getRefData().getCount(); runtime.push (sum); @@ -105,7 +105,7 @@ namespace MWScript for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; ++iter) { - if (Misc::toLower(iter->getCellRef().mRefID) == Misc::toLower(item)) + if (Misc::StringUtils::toLower(iter->getCellRef().mRefID) == Misc::StringUtils::toLower(item)) { itemName = MWWorld::Class::get(*iter).getName(*iter); @@ -163,7 +163,7 @@ namespace MWScript MWWorld::ContainerStoreIterator it = invStore.begin(); for (; it != invStore.end(); ++it) { - if (toLower(it->getCellRef().mRefID) == toLower(item)) + if (Misc::StringUtils::toLower(it->getCellRef().mRefID) == Misc::StringUtils::toLower(item)) break; } if (it == invStore.end()) @@ -263,7 +263,7 @@ namespace MWScript for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) { MWWorld::ContainerStoreIterator it = invStore.getSlot (slot); - if (it != invStore.end() && toLower(it->getCellRef().mRefID) == toLower(item)) + if (it != invStore.end() && Misc::StringUtils::toLower(it->getCellRef().mRefID) == Misc::StringUtils::toLower(item)) { runtime.push(1); return; @@ -281,8 +281,9 @@ namespace MWScript virtual void execute(Interpreter::Runtime &runtime) { MWWorld::Ptr ptr = R()(runtime); - - std::string creatureName = toLower (runtime.getStringLiteral (runtime[0].mInteger)); + + const std::string &name = runtime.getStringLiteral (runtime[0].mInteger); + std::string creatureName = Misc::StringUtils::toLower (const_cast(name)); runtime.pop(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); @@ -290,7 +291,7 @@ namespace MWScript it != invStore.end(); ++it) { - if (toLower(it->getCellRef().mSoul) == toLower(creatureName)) + if (Misc::StringUtils::toLower(it->getCellRef().mSoul) == Misc::StringUtils::toLower(creatureName)) { runtime.push(1); return; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 83c6b20e5..e38fcf717 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -621,7 +621,7 @@ namespace MWWorld { if (isPlayer) if (!newCell.isExterior()) - changeToInteriorCell(Misc::toLower(newCell.mCell->mName), pos); + changeToInteriorCell(Misc::StringUtils::toLower(const_cast (newCell.mCell->mName)), pos); else { int cellX = newCell.mCell->getGridX(); diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp deleted file mode 100644 index f9f74244b..000000000 --- a/components/esm_store/reclists.hpp +++ /dev/null @@ -1,674 +0,0 @@ -#ifndef _GAME_ESM_RECLISTS_H -#define _GAME_ESM_RECLISTS_H - -#include "components/esm/records.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -using namespace boost::algorithm; - -namespace ESMS -{ - using namespace ESM; - - struct RecList - { - virtual ~RecList() {} - - virtual void load(ESMReader &esm, const std::string &id) = 0; - virtual int getSize() = 0; - virtual void listIdentifier (std::vector& identifier) const = 0; - - }; - - typedef std::map RecListList; - - template - struct RecListT : RecList - { - virtual ~RecListT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = Misc::toLower (id); - list[id2].load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = Misc::toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - // Same as RecListT, but does not case-smash the IDs - // Note that lookups (search or find) are still case insensitive - template - struct RecListCaseT : RecList - { - virtual ~RecListCaseT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - //std::string id2 = Misc::toLower (id); - - list[id].load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = Misc::toLower (id); - - for (typename MapType::const_iterator iter = list.begin(); - iter != list.end(); ++iter) - { - if (Misc::toLower(iter->first) == id2) - return &iter->second; - } - - return NULL; - } - - // non-const version - X* search(const std::string &id) - { - std::string id2 = Misc::toLower (id); - - for (typename MapType::iterator iter = list.begin(); - iter != list.end(); ++iter) - { - if (Misc::toLower(iter->first) == id2) - return &iter->second; - } - - return NULL; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - /// Modified version of RecListT for records, that need to store their own ID - template - struct RecListWithIDT : RecList - { - virtual ~RecListWithIDT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = Misc::toLower (id); - list[id2].mId = id2; - list[id2].load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = Misc::toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - // The only difference to the above is a slight change to the load() - // function. We might merge these together later, and store the id - // in all the structs. - template - struct RecIDListT : RecList - { - virtual ~RecIDListT() {} - - typedef std::map MapType; - - MapType list; - - void load(ESMReader &esm, const std::string &id) - { - std::string id2 = Misc::toLower (id); - X& ref = list[id2]; - - ref.mId = id; - ref.load(esm); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = Misc::toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - /* Land textures are indexed by an integer number - */ - struct LTexList : RecList - { - virtual ~LTexList() {} - - // TODO: For multiple ESM/ESP files we need one list per file. - std::vector ltex; - - LTexList() - { - // More than enough to hold Morrowind.esm. - ltex.reserve(128); - } - - const LandTexture* search(size_t index) const - { - assert(index < ltex.size()); - return <ex.at(index); - } - - int getSize() { return ltex.size(); } - int getSize() const { return ltex.size(); } - - virtual void listIdentifier (std::vector& identifier) const {} - - void load(ESMReader &esm, const std::string &id) - { - LandTexture lt; - lt.load(esm); - lt.mId = id; - - // Make sure we have room for the structure - if(lt.mIndex + 1 > (int)ltex.size()) - ltex.resize(lt.mIndex+1); - - // Store it - ltex[lt.mIndex] = lt; - } - }; - - /* Landscapes are indexed by the X,Y coordinates of the exterior - cell they belong to. - */ - struct LandList : RecList - { - virtual ~LandList() - { - for ( LandMap::iterator itr = lands.begin(); itr != lands.end(); ++itr ) - { - delete itr->second; - } - } - - // Map containing all landscapes - typedef std::pair LandCoord; - typedef std::map LandMap; - LandMap lands; - - int count; - LandList() : count(0) {} - int getSize() { return count; } - - virtual void listIdentifier (std::vector& identifier) const {} - - // Find land for the given coordinates. Return null if no mData. - Land *search(int x, int y) const - { - LandMap::const_iterator itr = lands.find(std::make_pair (x, y)); - if ( itr == lands.end() ) - { - return NULL; - } - - return itr->second; - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - - // Create the structure and load it. This actually skips the - // landscape data and remembers the file position for later. - Land *land = new Land(); - land->load(esm); - - // Store the structure - lands[std::make_pair (land->mX, land->mY)] = land; - } - }; - - struct ciLessBoost : std::binary_function -{ - bool operator() (const std::string & s1, const std::string & s2) const { - //case insensitive version of is_less - return lexicographical_compare(s1, s2, is_iless()); - } -}; - - - // Cells aren't simply indexed by name. Exterior cells are treated - // separately. - // TODO: case handling (cell names are case-insensitive, but they are also showen to the - // player, so we can't simply smash case. - struct CellList : RecList - { - // Total cell count. Used for statistics. - int count; - CellList() : count(0) {} - int getSize() { return count; } - - // List of interior cells. Indexed by cell name. - typedef std::map IntCells; - IntCells intCells; - - // List of exterior cells. Indexed as extCells[mX][mY]. - typedef std::map, ESM::Cell*> ExtCells; - ExtCells extCells; - - virtual void listIdentifier (std::vector& identifier) const - { - for (IntCells::const_iterator iter (intCells.begin()); iter!=intCells.end(); ++iter) - identifier.push_back (iter->first); - } - - virtual ~CellList() - { - for (IntCells::iterator it = intCells.begin(); it!=intCells.end(); ++it) - delete it->second; - - for (ExtCells::iterator it = extCells.begin(); it!=extCells.end(); ++it) - delete it->second; - } - - const ESM::Cell* searchInt(const std::string &id) const - { - IntCells::const_iterator iter = intCells.find(id); - - if (iter!=intCells.end()) - return iter->second; - - return 0; - } - - const ESM::Cell* findInt(const std::string &id) const - { - const ESM::Cell *cell = searchInt (id); - - if (!cell) - throw std::runtime_error ("Interior cell not found - " + id); - - return cell; - } - - const ESM::Cell *searchExt (int x, int y) const - { - ExtCells::const_iterator it = extCells.find (std::make_pair (x, y)); - - if (it==extCells.end()) - return 0; - - return it->second; - } - - const ESM::Cell *findExt (int x, int y) const - { - const ESM::Cell *cell = searchExt (x, y); - - if (!cell) - throw std::runtime_error ("Exterior cell not found"); - - return cell; - } - const ESM::Cell *searchExtByName (const std::string& id) const - { - for (ExtCells::const_iterator iter = extCells.begin(); iter!=extCells.end(); ++iter) - { - if (Misc::toLower (iter->second->mName) == Misc::toLower (id)) - return iter->second; - } - - return 0; - } - - const ESM::Cell *searchExtByRegion (const std::string& id) const - { - std::string id2 = Misc::toLower (id); - - for (ExtCells::const_iterator iter = extCells.begin(); iter!=extCells.end(); ++iter) - if (Misc::toLower (iter->second->mRegion)==id) - return iter->second; - - return 0; - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - - // All cells have a name record, even nameless exterior cells. - ESM::Cell *cell = new ESM::Cell; - cell->mName = id; - - // The cell itself takes care of all the hairy details - cell->load(esm); - - if(cell->mData.mFlags & ESM::Cell::Interior) - { - // Store interior cell by name - intCells[id] = cell; - } - else - { - // Store exterior cells by grid position - extCells[std::make_pair (cell->mData.mX, cell->mData.mY)] = cell; - } - } - }; - - struct PathgridList : RecList - { - int count; - - // List of grids for interior cells. Indexed by cell name. - typedef std::map IntGrids; - IntGrids intGrids; - - // List of grids for exterior cells. Indexed as extCells[mX][mY]. - typedef std::map, ESM::Pathgrid*> ExtGrids; - ExtGrids extGrids; - - PathgridList() : count(0) {} - - virtual ~PathgridList() - { - for (IntGrids::iterator it = intGrids.begin(); it!=intGrids.end(); ++it) - delete it->second; - - for (ExtGrids::iterator it = extGrids.begin(); it!=extGrids.end(); ++it) - delete it->second; - } - - int getSize() { return count; } - - virtual void listIdentifier (std::vector& identifier) const - { - // do nothing - } - - void load(ESMReader &esm, const std::string &id) - { - count++; - ESM::Pathgrid *grid = new ESM::Pathgrid; - grid->load(esm); - if (grid->mData.mX == 0 && grid->mData.mY == 0) - { - intGrids[grid->mCell] = grid; - } - else - { - extGrids[std::make_pair(grid->mData.mX, grid->mData.mY)] = grid; - } - } - - Pathgrid *find(int cellX, int cellY, const std::string &cellName) const - { - Pathgrid *result = search(cellX, cellY, cellName); - if (!result) - { - throw std::runtime_error("no pathgrid found for cell " + cellName); - } - return result; - } - - Pathgrid *search(int cellX, int cellY, const std::string &cellName) const - { - Pathgrid *result = NULL; - if (cellX == 0 && cellY == 0) // possibly interior - { - IntGrids::const_iterator it = intGrids.find(cellName); - if (it != intGrids.end()) - result = it->second; - } - else - { - ExtGrids::const_iterator it = extGrids.find(std::make_pair(cellX, cellY)); - if (it != extGrids.end()) - result = it->second; - } - return result; - } - - Pathgrid *search(const ESM::Cell &cell) const - { - int cellX, cellY; - if (cell.mData.mFlags & ESM::Cell::Interior) - { - cellX = cellY = 0; - } - else - { - cellX = cell.mData.mX; - cellY = cell.mData.mY; - } - return search(cellX, cellY, cell.mName); - } - }; - - template - struct ScriptListT : RecList - { - virtual ~ScriptListT() {} - - typedef std::map MapType; - - MapType list; - - // Load one object of this type - void load(ESMReader &esm, const std::string &id) - { - X ref; - ref.load (esm); - - std::string realId = Misc::toLower (ref.mData.mName.toString()); - - std::swap (list[realId], ref); - } - - // Find the given object ID, or return NULL if not found. - const X* search(const std::string &id) const - { - std::string id2 = Misc::toLower (id); - - typename MapType::const_iterator iter = list.find (id2); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find(const std::string &id) const - { - const X *object = search (id); - - if (!object) - throw std::runtime_error ("object " + id + " not found"); - - return object; - } - - int getSize() { return list.size(); } - - virtual void listIdentifier (std::vector& identifier) const - { - for (typename MapType::const_iterator iter (list.begin()); iter!=list.end(); ++iter) - identifier.push_back (iter->first); - } - }; - - template - struct IndexListT - { - virtual ~IndexListT() {} - - typedef std::map MapType; - - MapType list; - - void load(ESMReader &esm) - { - X ref; - ref.load (esm); - int index = ref.mIndex; - list[index] = ref; - } - - int getSize() - { - return list.size(); - } - - virtual void listIdentifier (std::vector& identifier) const {} - - // Find the given object ID, or return NULL if not found. - const X* search (int id) const - { - typename MapType::const_iterator iter = list.find (id); - - if (iter == list.end()) - return NULL; - - return &iter->second; - } - - // Find the given object ID (throws an exception if not found) - const X* find (int id) const - { - const X *object = search (id); - - if (!object) - { - std::ostringstream error; - error << "object " << id << " not found"; - throw std::runtime_error (error.str()); - } - - return object; - } - }; - - /* We need special lists for: - - Path grids - */ -} -#endif diff --git a/components/misc/stringops.cpp b/components/misc/stringops.cpp index 51cf2105a..0bc8e290a 100644 --- a/components/misc/stringops.cpp +++ b/components/misc/stringops.cpp @@ -67,30 +67,4 @@ bool iends(const char* str1, const char* str2) return strcasecmp(str2, str1+len1-len2) == 0; } -std::string toLower (const std::string& name) -{ - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; -} - -bool stringCompareNoCase (std::string first, std::string second) -{ - unsigned int i=0; - while ( (itolower(second[i])) return false; - ++i; - } - if (first.length() Date: Mon, 31 Dec 2012 04:15:47 +0400 Subject: [PATCH 212/916] 1. Dialogs in Russian version now works. 2. Destination names it travel window are now translated --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 4 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 103 ++++++++++++++++-- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 19 +++- apps/openmw/mwgui/dialogue.cpp | 83 ++++++++++++-- apps/openmw/mwgui/dialogue.hpp | 12 +- apps/openmw/mwgui/travelwindow.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 5 + apps/openmw/mwgui/windowmanagerimp.hpp | 2 + components/translation/translation.cpp | 30 +++-- components/translation/translation.hpp | 7 +- 11 files changed, 236 insertions(+), 33 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b995300d5..e2d28a808 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -360,7 +360,7 @@ void OMW::Engine::go() // Create dialog system mEnvironment.setJournal (new MWDialogue::Journal); - mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts)); + mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); // Sets up the input system mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c177912d4..30bfced06 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -7,6 +7,8 @@ #include +#include + #include "../mwmechanics/stat.hpp" #include "../mwgui/mode.hpp" @@ -233,6 +235,8 @@ namespace MWBase virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; + + virtual const Translation::Storage& getTranslationDataStorage() const = 0; }; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 26d5af202..68837be3c 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -52,7 +52,7 @@ namespace return lowerCase; } - bool stringCompareNoCase (std::string first, std::string second) + bool stringCompareNoCase (const std::string& first, const std::string& second) { unsigned int i=0; while ( (i::iterator it; - for(it = mActorKnownTopics.begin();it != mActorKnownTopics.end();++it) + std::vector hypertext = ParseHyperText(text); + + //calculation of standard form fir all hyperlinks + for (size_t i = 0; i < hypertext.size(); ++i) { - size_t pos = find_str_ci(text,*it,0); - if(pos !=std::string::npos) + if (hypertext[i].mLink) { - mKnownTopics[*it] = true; + size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); + for(; asterisk_count > 0; --asterisk_count) + hypertext[i].mText.append("*"); + + hypertext[i].mText = mTranslationDataStorage.topicStandardForm(hypertext[i].mText); } } + + for (size_t i = 0; i < hypertext.size(); ++i) + { + std::list::iterator it; + for(it = mActorKnownTopics.begin(); it != mActorKnownTopics.end(); ++it) + { + if (hypertext[i].mLink) + { + if( hypertext[i].mText == *it ) + { + mKnownTopics[hypertext[i].mText] = true; + } + } + else if( !mTranslationDataStorage.hasTranslation() ) + { + size_t pos = find_str_ci(hypertext[i].mText, *it, 0); + if(pos !=std::string::npos) + { + mKnownTopics[*it] = true; + } + } + } + } + updateTopics(); } @@ -156,7 +186,7 @@ namespace MWDialogue } parseText (info->mResponse); - + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); @@ -298,7 +328,7 @@ namespace MWDialogue { if (filter.search (*iter)) { - mActorKnownTopics.push_back (toLower (iter->mId)); + mActorKnownTopics.push_back(toLower (iter->mId)); //does the player know the topic? if (mKnownTopics.find (toLower (iter->mId)) != mKnownTopics.end()) @@ -415,7 +445,7 @@ namespace MWDialogue mIsInChoice = false; std::string text = info->mResponse; parseText (text); - + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); executeScript (info->mResultScript); @@ -499,4 +529,57 @@ namespace MWDialogue { mTemporaryDispositionChange += delta; } + + std::vector ParseHyperText(const std::string& text) + { + std::vector result; + + MyGUI::UString utext(text); + + size_t pos_begin, pos_end, iteration_pos = 0; + for(;;) + { + pos_begin = utext.find('@', iteration_pos); + if (pos_begin != std::string::npos) + pos_end = utext.find('#', pos_begin); + + if (pos_begin != std::string::npos && pos_end != std::string::npos) + { + result.push_back( HyperTextToken(utext.substr(iteration_pos, pos_begin - iteration_pos), false) ); + + std::string link = utext.substr(pos_begin + 1, pos_end - pos_begin - 1); + result.push_back( HyperTextToken(link, true) ); + + iteration_pos = pos_end + 1; + } + else + { + result.push_back( HyperTextToken(utext.substr(iteration_pos), false) ); + break; + } + } + + return result; + } + + size_t RemovePseudoAsterisks(std::string& phrase) + { + size_t pseudoAsterisksCount = 0; + const char specialPseudoAsteriskCharacter = 127; + + if( !phrase.empty() ) + { + std::string::reverse_iterator rit = phrase.rbegin(); + + while( rit != phrase.rend() && *rit == specialPseudoAsteriskCharacter ) + { + pseudoAsterisksCount++; + ++rit; + } + } + + phrase = phrase.substr(0, phrase.length() - pseudoAsterisksCount); + + return pseudoAsterisksCount; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 98b27f774..1ca2ae5eb 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -20,6 +21,7 @@ namespace MWDialogue std::map mKnownTopics;// Those are the topics the player knows. std::list mActorKnownTopics; + Translation::Storage& mTranslationDataStorage; MWScript::CompilerContext mCompilerContext; std::ostream mErrorStream; Compiler::StreamErrorHandler mErrorHandler; @@ -50,7 +52,7 @@ namespace MWDialogue public: - DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose); + DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage); virtual void startDialogue (const MWWorld::Ptr& actor); @@ -72,6 +74,21 @@ namespace MWDialogue virtual int getTemporaryDispositionChange () const; virtual void applyTemporaryDispositionChange (int delta); }; + + + struct HyperTextToken + { + HyperTextToken(const std::string& text, bool link) : mText(text), mLink(link) {} + + std::string mText; + bool mLink; + }; + + // In translations (at least Russian) the links are marked with @#, so + // it should be a function to parse it + std::vector ParseHyperText(const std::string& text); + + size_t RemovePseudoAsterisks(std::string& phrase); } #endif diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 258e9174c..0dbe37941 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -16,6 +16,8 @@ #include "../mwmechanics/npcstats.hpp" +#include "../mwdialogue/dialoguemanagerimp.hpp" + #include "dialogue_history.hpp" #include "widgets.hpp" #include "list.hpp" @@ -52,7 +54,6 @@ bool sortByLength (const std::string& left, const std::string& right) { return left.size() > right.size(); } - } @@ -131,6 +132,7 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) , mPersuasionDialog(parWindowManager) , mEnabled(false) , mServices(0) + , mWindowManager(parWindowManager) { // Centre dialog center(); @@ -180,9 +182,30 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) if(color != "#B29154") { MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); - if(color == "#686EBA") MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); - if(color == "#572D21") MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); + if(color == "#686EBA") + { + std::map::iterator i = mHyperLinks.upper_bound(cursorPosition); + if( !mHyperLinks.empty() ) + { + --i; + + if( i->first + i->second.mLength > cursorPosition) + { + MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue); + } + } + else + { + // the link was colored, but it is not in mHyperLinks. + // It means that those liunks are not marked with @# and found + // by topic name search + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); + } + } + + if(color == "#572D21") + MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); } } @@ -258,6 +281,7 @@ void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) setTitle(npcName); mTopicsList->clear(); + mHyperLinks.clear(); mHistory->setCaption(""); updateOptions(); } @@ -340,7 +364,7 @@ void addColorInString(std::string& str, const std::string& keyword,std::string c } } -std::string DialogueWindow::parseText(std::string text) +std::string DialogueWindow::parseText(const std::string& text) { bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) @@ -358,11 +382,55 @@ std::string DialogueWindow::parseText(std::string text) // sort by length to make sure longer topics are replaced first std::sort(topics.begin(), topics.end(), sortByLength); - for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + std::vector hypertext = MWDialogue::ParseHyperText(text); + + size_t historySize = 0; + if(mHistory->getClient()->getSubWidgetText() != nullptr) { - addColorInString(text,*it,"#686EBA","#B29154"); + historySize = mHistory->getOnlyText().size(); } - return text; + + std::string result; + size_t hypertextPos = 0; + for (size_t i = 0; i < hypertext.size(); ++i) + { + if (hypertext[i].mLink) + { + size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); + std::string standardForm = hypertext[i].mText; + for(; asterisk_count > 0; --asterisk_count) + standardForm.append("*"); + + standardForm = + mWindowManager.getTranslationDataStorage().topicStandardForm(standardForm); + + if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() ) + { + result.append("#686EBA").append(hypertext[i].mText).append("#B29154"); + + mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length(); + mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm); + } + else + result += hypertext[i].mText; + } + else + { + if( !mWindowManager.getTranslationDataStorage().hasTranslation() ) + { + for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + { + addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154"); + } + } + + result += hypertext[i].mText; + } + + hypertextPos += MyGUI::UString(hypertext[i].mText).length(); + } + + return result; } void DialogueWindow::addText(std::string text) @@ -394,6 +462,7 @@ void DialogueWindow::updateOptions() { //Clear the list of topics mTopicsList->clear(); + mHyperLinks.clear(); mHistory->eraseText(0, mHistory->getTextLength()); if (mPtr.getTypeName() == typeid(ESM::NPC).name()) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 082d92524..3eeea01cd 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -92,12 +92,18 @@ namespace MWGui virtual void onReferenceUnavailable(); + struct HyperLink + { + size_t mLength; + std::string mTrueValue; + }; + private: void updateOptions(); /** *Helper function that add topic keyword in blue in a text. */ - std::string parseText(std::string text); + std::string parseText(const std::string& text); int mServices; @@ -109,6 +115,10 @@ namespace MWGui MyGUI::EditPtr mDispositionText; PersuasionDialog mPersuasionDialog; + + MWBase::WindowManager& mWindowManager; + + std::map mHyperLinks; }; } #endif diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index abbc6172f..9615e95f7 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -82,7 +82,7 @@ namespace MWGui oss << price; toAdd->setUserString("price",oss.str()); - toAdd->setCaptionWithReplacing(travelId+" - "+boost::lexical_cast(price)+"#{sgp}"); + toAdd->setCaptionWithReplacing("#{sCell=" + travelId + "} - " + boost::lexical_cast(price)+"#{sgp}"); toAdd->setSize(toAdd->getTextSize().width,sLineHeight); toAdd->eventMouseWheel += MyGUI::newDelegate(this, &TravelWindow::onMouseWheel); toAdd->setUserString("Destination", travelId); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index caf6a4ab0..12e72eaa9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1050,3 +1050,8 @@ void WindowManager::startTraining(MWWorld::Ptr actor) { mTrainingWindow->startTraining(actor); } + +const Translation::Storage& WindowManager::getTranslationDataStorage() const +{ + return mTranslationDataStorage; +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index aaa856aef..8bcb88e22 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -225,6 +225,8 @@ namespace MWGui virtual void startEnchanting(MWWorld::Ptr actor); virtual void startTraining(MWWorld::Ptr actor); + virtual const Translation::Storage& getTranslationDataStorage() const; + private: OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index b559c6c1c..fb5b03861 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -81,17 +81,7 @@ namespace Translation std::string Storage::topicID(const std::string& phrase) const { - std::string result; - - //seeking for the standard phrase form - std::map::const_iterator phraseFormsIterator = - mPhraseForms.find(phrase); - - if (phraseFormsIterator != mPhraseForms.end()) - result = phraseFormsIterator->second; - else - result = phrase; - + std::string result = topicStandardForm(phrase); //seeking for the topic ID std::map::const_iterator topicIDIterator = @@ -103,8 +93,26 @@ namespace Translation return result; } + std::string Storage::topicStandardForm(const std::string& phrase) const + { + std::map::const_iterator phraseFormsIterator = + mPhraseForms.find(phrase); + + if (phraseFormsIterator != mPhraseForms.end()) + return phraseFormsIterator->second; + else + return phrase; + } + void Storage::setEncoding (const ToUTF8::FromType& encoding) { mEncoding = encoding; } + + bool Storage::hasTranslation() const + { + return !mCellNamesTranslations.empty() || + !mTopicIDs.empty() || + !mPhraseForms.empty(); + } } diff --git a/components/translation/translation.hpp b/components/translation/translation.hpp index 668d4c067..80d44d871 100644 --- a/components/translation/translation.hpp +++ b/components/translation/translation.hpp @@ -16,8 +16,13 @@ namespace Translation std::string translateCellName(const std::string& cellName) const; std::string topicID(const std::string& phrase) const; + // Standard form usually means nominative case + std::string topicStandardForm(const std::string& phrase) const; + void setEncoding (const ToUTF8::FromType& encoding); + bool hasTranslation() const; + private: typedef std::map ContainerType; @@ -30,7 +35,7 @@ namespace Translation ToUTF8::FromType mEncoding; - std::map mCellNamesTranslations, mTopicIDs, mPhraseForms; + ContainerType mCellNamesTranslations, mTopicIDs, mPhraseForms; }; } From 7e0713f6c4d414a0df087f7d4954c36709b02ce0 Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 31 Dec 2012 11:22:40 +0400 Subject: [PATCH 213/916] fix string case update --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 23 ++++++------------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 1 - apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwscript/containerextensions.cpp | 13 +++++------ apps/openmw/mwworld/worldimp.cpp | 2 +- 5 files changed, 15 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 80999c5ff..d81421f81 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -40,16 +40,6 @@ #include "filter.hpp" -namespace -{ - - //helper function - std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) - { - return Misc::StringUtils::toLower(const_cast(str)).find(Misc::StringUtils::toLower(const_cast(substr)).c_str(),pos); - } -} - namespace MWDialogue { DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose) : @@ -70,13 +60,13 @@ namespace MWDialogue MWWorld::Store::iterator it = dialogs.begin(); for (; it != dialogs.end(); ++it) { - mDialogueMap[Misc::StringUtils::toLower(const_cast(it->mId))] = *it; + mDialogueMap[Misc::StringUtils::lowerCase(it->mId)] = *it; } } void DialogueManager::addTopic (const std::string& topic) { - mKnownTopics[Misc::StringUtils::toLower(const_cast(topic))] = true; + mKnownTopics[Misc::StringUtils::lowerCase(topic)] = true; } void DialogueManager::parseText (const std::string& text) @@ -84,7 +74,7 @@ namespace MWDialogue std::list::iterator it; for(it = mActorKnownTopics.begin();it != mActorKnownTopics.end();++it) { - size_t pos = find_str_ci(text,*it,0); + size_t pos = Misc::StringUtils::lowerCase(text).find(*it, 0); if(pos !=std::string::npos) { mKnownTopics[*it] = true; @@ -274,10 +264,11 @@ namespace MWDialogue { if (filter.search (*iter)) { - mActorKnownTopics.push_back ( Misc::StringUtils::toLower(const_cast(iter->mId))); + std::string lower = Misc::StringUtils::lowerCase(iter->mId); + mActorKnownTopics.push_back (lower); //does the player know the topic? - if (mKnownTopics.find ( Misc::StringUtils::toLower(const_cast(iter->mId))) != mKnownTopics.end()) + if (mKnownTopics.find (lower) != mKnownTopics.end()) { keywordList.push_back (iter->mId); } @@ -415,7 +406,7 @@ namespace MWDialogue { MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->askQuestion(question); - mChoiceMap[Misc::StringUtils::toLower(const_cast(question))] = choice; + mChoiceMap[Misc::StringUtils::lowerCase(question)] = choice; mIsInChoice = true; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index b0bef5ea0..98b27f774 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -71,7 +71,6 @@ namespace MWDialogue virtual void persuade (int type); virtual int getTemporaryDispositionChange () const; virtual void applyTemporaryDispositionChange (int delta); - void toLower(std::string question); }; } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index dd75b8216..ffb6c5282 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -271,7 +271,7 @@ namespace MWGui for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { - if (Misc::StringUtils::toLower(it->getCellRef().mRefID) == "gold_001") + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) return it->getRefData().getCount(); } return 0; diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 2cdad2a90..1fa69d1fd 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -72,7 +72,7 @@ namespace MWScript Interpreter::Type_Integer sum = 0; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (Misc::StringUtils::toLower(iter->getCellRef().mRefID) == Misc::StringUtils::toLower(item)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) sum += iter->getRefData().getCount(); runtime.push (sum); @@ -105,7 +105,7 @@ namespace MWScript for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; ++iter) { - if (Misc::StringUtils::toLower(iter->getCellRef().mRefID) == Misc::StringUtils::toLower(item)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) { itemName = MWWorld::Class::get(*iter).getName(*iter); @@ -163,7 +163,7 @@ namespace MWScript MWWorld::ContainerStoreIterator it = invStore.begin(); for (; it != invStore.end(); ++it) { - if (Misc::StringUtils::toLower(it->getCellRef().mRefID) == Misc::StringUtils::toLower(item)) + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item)) break; } if (it == invStore.end()) @@ -263,7 +263,7 @@ namespace MWScript for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) { MWWorld::ContainerStoreIterator it = invStore.getSlot (slot); - if (it != invStore.end() && Misc::StringUtils::toLower(it->getCellRef().mRefID) == Misc::StringUtils::toLower(item)) + if (it != invStore.end() && Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item)) { runtime.push(1); return; @@ -282,8 +282,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - const std::string &name = runtime.getStringLiteral (runtime[0].mInteger); - std::string creatureName = Misc::StringUtils::toLower (const_cast(name)); + const std::string &name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); @@ -291,7 +290,7 @@ namespace MWScript it != invStore.end(); ++it) { - if (Misc::StringUtils::toLower(it->getCellRef().mSoul) == Misc::StringUtils::toLower(creatureName)) + if (Misc::StringUtils::ciEqual(it->getCellRef().mSoul, name)) { runtime.push(1); return; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e38fcf717..3995123b0 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -621,7 +621,7 @@ namespace MWWorld { if (isPlayer) if (!newCell.isExterior()) - changeToInteriorCell(Misc::StringUtils::toLower(const_cast (newCell.mCell->mName)), pos); + changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos); else { int cellX = newCell.mCell->getGridX(); From e2b348de9620c23695064f585d7ea4600b2abe88 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Mon, 31 Dec 2012 16:44:22 +0100 Subject: [PATCH 214/916] mwiniimporter: fix line ending problem --- apps/mwiniimporter/importer.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index dda8fd8ba..30822516e 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -660,10 +660,19 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) { std::string line; while (std::getline(file, line)) { + // unify Unix-style and Windows file ending + if (!(line.empty()) && (line[line.length()-1]) == '\r') { + line = line.substr(0, line.length()-1); + } + if(line[0] == '[') { - if(line.length() > 2) { - section = line.substr(1, line.length()-2); + int pos = line.find(']'); + if(pos < 2) { + std::cout << "Warning: ini file wrongly formatted (" << line << "). Line ignored." << std::endl; + continue; } + + section = line.substr(1, line.find(']')-1); continue; } From e9a464c9f7463c175f38e4966600ef3f839f68d1 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Mon, 31 Dec 2012 16:45:24 +0100 Subject: [PATCH 215/916] mwiniimporter: remove fallback values for Cursors --- apps/mwiniimporter/importer.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 30822516e..c15818ae3 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -146,13 +146,6 @@ MwIniImporter::MwIniImporter() "FontColor:color_negative", "FontColor:color_count", - // cursors - "Cursors:Cursor 0", - "Cursors:Cursor 1", - "Cursors:Cursor 2", - "Cursors:Cursor 3", - "Cursors:Cursor 4", - // level up messages "Level Up:Level2", "Level Up:Level3", From 008d6d6589e9709efdede92a94f1bd706df9fe06 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 30 Dec 2012 14:59:09 -0800 Subject: [PATCH 216/916] added additional library search paths to find bullet This allowed CMake to correctly build Visual Studio 2010 project files against a windows compiled version of bullet (2.81 rev 2613) --- cmake/FindBullet.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/FindBullet.cmake b/cmake/FindBullet.cmake index 8d5ea2f1e..97feddffe 100644 --- a/cmake/FindBullet.cmake +++ b/cmake/FindBullet.cmake @@ -27,6 +27,8 @@ macro(_FIND_BULLET_LIBRARY _var) ${ARGN} PATHS ${BULLET_ROOT} + ${BULLET_ROOT}/lib/Debug + ${BULLET_ROOT}/lib/Release ${BULLET_ROOT}/out/release8/libs ${BULLET_ROOT}/out/debug8/libs PATH_SUFFIXES lib From 7228f5d696fa641a0bced370b86bb875330f2534 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 30 Dec 2012 21:16:54 -0800 Subject: [PATCH 217/916] added missing reference to added missing reference to that was causing Visual Studio 2010 to fail to compile stringops.hpp --- components/misc/stringops.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 112d66bb8..029b617e1 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -1,6 +1,7 @@ #ifndef MISC_STRINGOPS_H #define MISC_STRINGOPS_H +#include #include #include From a842fc2c11e30d189a41be930cf9db55eaddddfa Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 30 Dec 2012 22:02:55 -0800 Subject: [PATCH 218/916] added hack to fix an alignment issue in MSVC 2010 The default allocator in Visual Studio 2010 does not respect the alignment requirements of classes it is allocating memory for. This results in a potential crash when using OEngine::Physics::PhysicActor that has been allocated on the heap if it is built against a version of Bullet that has SSE intrinsics enabled. --- libs/openengine/bullet/physic.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index f320d009d..76bdb491d 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -122,8 +122,13 @@ namespace Physic */ void runPmove(); - - +//HACK: in Visual Studio 2010 and presumably above, this structures alignment +// must be 16, but the built in operator new & delete don't properly +// perform this alignment. +#if _MSC_VER >= 1600 + void * operator new (size_t Size) { return _aligned_malloc (Size, 16); } + void operator delete (void * Data) { _aligned_free (Data); } +#endif private: From 08fa9dcd3ebe6a92eb38be671dfe63800647c4fc Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 1 Jan 2013 11:59:05 -0800 Subject: [PATCH 219/916] replaced std::string concatenation with std::ostringstream Changed a block of code that was performing a series of string concatenations to use an ostringstream instead. This allowed the removal of calls to std::to_string (not C++03 compliant) and fixes an compile error in MSVC 2010 (ambigous overload when calling std::to_string). --- components/interpreter/defines.cpp | 87 +++++++++++++++--------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp index 29c78200d..18e5f81c1 100644 --- a/components/interpreter/defines.cpp +++ b/components/interpreter/defines.cpp @@ -1,6 +1,7 @@ #include "defines.hpp" #include +#include #include #include @@ -24,113 +25,113 @@ namespace Interpreter{ std::string fixDefinesReal(std::string text, char eschar, bool isBook, Context& context){ unsigned int start = 0; - std::string retval = ""; + std::ostringstream retval; for(unsigned int i = 0; i < text.length(); i++){ if(text[i] == eschar){ - retval += text.substr(start, i - start); + retval << text.substr(start, i - start); std::string temp = text.substr(i+1, 100); transform(temp.begin(), temp.end(), temp.begin(), ::tolower); bool found; if( (found = Check(temp, "actionslideright", &i, &start))){ - retval += context.getActionBinding("#{sRight}"); + retval << context.getActionBinding("#{sRight}"); } else if((found = Check(temp, "actionreadymagic", &i, &start))){ - retval += context.getActionBinding("#{sReady_Magic}"); + retval << context.getActionBinding("#{sReady_Magic}"); } else if((found = Check(temp, "actionprevweapon", &i, &start))){ - retval += "PLACEHOLDER_ACTION_PREV_WEAPON"; + retval << "PLACEHOLDER_ACTION_PREV_WEAPON"; } else if((found = Check(temp, "actionnextweapon", &i, &start))){ - retval += "PLACEHOLDER_ACTION_PREV_WEAPON"; + retval << "PLACEHOLDER_ACTION_PREV_WEAPON"; } else if((found = Check(temp, "actiontogglerun", &i, &start))){ - retval += context.getActionBinding("#{sAuto_Run}"); + retval << context.getActionBinding("#{sAuto_Run}"); } else if((found = Check(temp, "actionslideleft", &i, &start))){ - retval += context.getActionBinding("#{sLeft}"); + retval << context.getActionBinding("#{sLeft}"); } else if((found = Check(temp, "actionreadyitem", &i, &start))){ - retval += context.getActionBinding("#{sReady_Weapon}"); + retval << context.getActionBinding("#{sReady_Weapon}"); } else if((found = Check(temp, "actionprevspell", &i, &start))){ - retval += "PLACEHOLDER_ACTION_PREV_SPELL"; + retval << "PLACEHOLDER_ACTION_PREV_SPELL"; } else if((found = Check(temp, "actionnextspell", &i, &start))){ - retval += "PLACEHOLDER_ACTION_NEXT_SPELL"; + retval << "PLACEHOLDER_ACTION_NEXT_SPELL"; } else if((found = Check(temp, "actionrestmenu", &i, &start))){ - retval += context.getActionBinding("#{sRestKey}"); + retval << context.getActionBinding("#{sRestKey}"); } else if((found = Check(temp, "actionmenumode", &i, &start))){ - retval += context.getActionBinding("#{sJournal}"); + retval << context.getActionBinding("#{sJournal}"); } else if((found = Check(temp, "actionactivate", &i, &start))){ - retval += context.getActionBinding("#{sActivate}"); + retval << context.getActionBinding("#{sActivate}"); } else if((found = Check(temp, "actionjournal", &i, &start))){ - retval += context.getActionBinding("#{sJournal}"); + retval << context.getActionBinding("#{sJournal}"); } else if((found = Check(temp, "actionforward", &i, &start))){ - retval += context.getActionBinding("#{sForward}"); + retval << context.getActionBinding("#{sForward}"); } else if((found = Check(temp, "pccrimelevel", &i, &start))){ - retval += std::to_string(context.getPCBounty()); + retval << context.getPCBounty(); } else if((found = Check(temp, "actioncrouch", &i, &start))){ - retval += context.getActionBinding("#{sCrouch_Sneak}"); + retval << context.getActionBinding("#{sCrouch_Sneak}"); } else if((found = Check(temp, "actionjump", &i, &start))){ - retval += context.getActionBinding("#{sJump}"); + retval << context.getActionBinding("#{sJump}"); } else if((found = Check(temp, "actionback", &i, &start))){ - retval += context.getActionBinding("#{sBack}"); + retval << context.getActionBinding("#{sBack}"); } else if((found = Check(temp, "actionuse", &i, &start))){ - retval += "PLACEHOLDER_ACTION_USE"; + retval << "PLACEHOLDER_ACTION_USE"; } else if((found = Check(temp, "actionrun", &i, &start))){ - retval += "PLACEHOLDER_ACTION_RUN"; + retval << "PLACEHOLDER_ACTION_RUN"; } else if((found = Check(temp, "pcclass", &i, &start))){ - retval += context.getPCClass(); + retval << context.getPCClass(); } else if((found = Check(temp, "pcrace", &i, &start))){ - retval += context.getPCRace(); + retval << context.getPCRace(); } else if((found = Check(temp, "pcname", &i, &start))){ - retval += context.getPCName(); + retval << context.getPCName(); } else if((found = Check(temp, "cell", &i, &start))){ - retval += context.getCurrentCellName(); + retval << context.getCurrentCellName(); } else if(eschar == '%' && !isBook) { // In Dialogue, not messagebox if( (found = Check(temp, "faction", &i, &start))){ - retval += context.getNPCFaction(); + retval << context.getNPCFaction(); } else if((found = Check(temp, "nextpcrank", &i, &start))){ - retval += context.getPCNextRank(); + retval << context.getPCNextRank(); } else if((found = Check(temp, "pcnextrank", &i, &start))){ - retval += context.getPCNextRank(); + retval << context.getPCNextRank(); } else if((found = Check(temp, "pcrank", &i, &start))){ - retval += context.getPCRank(); + retval << context.getPCRank(); } else if((found = Check(temp, "rank", &i, &start))){ - retval += context.getNPCRank(); + retval << context.getNPCRank(); } else if((found = Check(temp, "class", &i, &start))){ - retval += context.getNPCClass(); + retval << context.getNPCClass(); } else if((found = Check(temp, "race", &i, &start))){ - retval += context.getNPCRace(); + retval << context.getNPCRace(); } else if((found = Check(temp, "name", &i, &start))){ - retval += context.getNPCName(); + retval << context.getNPCName(); } } else { // In messagebox or book, not dialogue @@ -144,13 +145,13 @@ namespace Interpreter{ /* uses pc in messageboxes */ else if((found = Check(temp, "class", &i, &start))){ - retval += context.getPCClass(); + retval << context.getPCClass(); } else if((found = Check(temp, "race", &i, &start))){ - retval += context.getPCRace(); + retval << context.getPCRace(); } else if((found = Check(temp, "name", &i, &start))){ - retval += context.getPCName(); + retval << context.getPCName(); } } @@ -172,9 +173,9 @@ namespace Interpreter{ char type = context.getGlobalType(globals[j]); switch(type){ - case 's': retval += std::to_string(context.getGlobalShort(globals[j])); break; - case 'l': retval += std::to_string(context.getGlobalLong(globals[j])); break; - case 'f': retval += std::to_string(context.getGlobalFloat(globals[j])); break; + case 's': retval << context.getGlobalShort(globals[j]); break; + case 'l': retval << context.getGlobalLong(globals[j]); break; + case 'f': retval << context.getGlobalFloat(globals[j]); break; } break; } @@ -186,12 +187,12 @@ namespace Interpreter{ /* leave unmodified */ i += 1; start = i; - retval += eschar; + retval << eschar; } } } - retval += text.substr(start, text.length() - start); - return retval; + retval << text.substr(start, text.length() - start); + return retval.str (); } std::string fixDefinesDialog(std::string text, Context& context){ From 2a7336c310eb668015e39265c5e4f4f2d1216edb Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 1 Jan 2013 21:59:30 +0100 Subject: [PATCH 220/916] mwiniimporter: handle ini file encodings Use components/to_utf8 to handle encodings. Add an --encoding option for choosing between win1250, win1251 and win1252 encodings for the imported ini file. --- apps/mwiniimporter/importer.cpp | 15 +++++++++++++++ apps/mwiniimporter/importer.hpp | 5 +++++ apps/mwiniimporter/main.cpp | 9 +++++++++ 3 files changed, 29 insertions(+) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index c15818ae3..def70615b 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -653,6 +653,8 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) { std::string line; while (std::getline(file, line)) { + line = toUTF8(line); + // unify Unix-style and Windows file ending if (!(line.empty()) && (line[line.length()-1]) == '\r') { line = line.substr(0, line.length()-1); @@ -826,3 +828,16 @@ void MwIniImporter::writeToFile(boost::iostreams::stream #include +#include "../../components/to_utf8/to_utf8.hpp" + class MwIniImporter { public: typedef std::map strmap; typedef std::map > multistrmap; MwIniImporter(); + void setInputEncoding(const ToUTF8::FromType& encoding); void setVerbose(bool verbose); multistrmap loadIniFile(std::string filename); multistrmap loadCfgFile(std::string filename); @@ -25,9 +28,11 @@ class MwIniImporter { private: void insertMultistrmap(multistrmap &cfg, std::string key, std::string value); std::string numberToString(int n); + std::string toUTF8(const std::string &str); bool mVerbose; strmap mMergeMap; std::vector mMergeFallback; + ToUTF8::FromType mEncoding; }; diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 234d7d57d..e90f26dd2 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -18,6 +18,11 @@ int main(int argc, char *argv[]) { ("cfg,c", bpo::value(), "openmw.cfg file") ("output,o", bpo::value()->default_value(""), "openmw.cfg file") ("game-files,g", "import esm and esp files") + ("encoding,e", bpo::value()-> default_value("win1252"), + "Character encoding used in OpenMW game messages:\n" + "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" + "\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n" + "\n\twin1252 - Western European (Latin) alphabet, used by default") ; p_desc.add("ini", 1).add("cfg", 1); @@ -57,6 +62,10 @@ int main(int argc, char *argv[]) { MwIniImporter importer; importer.setVerbose(vm.count("verbose")); + // Font encoding settings + std::string encoding(vm["encoding"].as()); + importer.setInputEncoding(ToUTF8::calculateEncoding(encoding)); + MwIniImporter::multistrmap ini = importer.loadIniFile(iniFile); MwIniImporter::multistrmap cfg = importer.loadCfgFile(cfgFile); From 86f30992d7f1979f3ac187add917e793a1671c1b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 1 Jan 2013 22:00:14 +0100 Subject: [PATCH 221/916] fix message boxes not appearing properly when e.g. trading --- apps/openmw/mwgui/windowmanagerimp.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6164f9037..7f5d34939 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -539,9 +539,8 @@ void WindowManager::messageBox (const std::string& message, const std::vectoraddMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); - else mMessageBoxManager->createMessageBox(message); } From c613f07b84f1ebabd758c1e4a993e883b22f7c1b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 2 Jan 2013 10:10:10 +0100 Subject: [PATCH 222/916] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 72451c3d0..713fbe9ac 100644 --- a/credits.txt +++ b/credits.txt @@ -32,6 +32,7 @@ Lukasz Gromanowski (lgro) Marcin Hulist (Gohan) Michael Mc Donnell Michael Papageorgiou (werdanith) +Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) Pieter van der Kloet (pvdk) Roman Melnik (Kromgart) From 04cca2a1ce85e73e9fe0d4a6e3b948b7ebf5d603 Mon Sep 17 00:00:00 2001 From: lazydev Date: Wed, 2 Jan 2013 18:58:52 +0400 Subject: [PATCH 223/916] fix for http://bugs.openmw.org/issues/517 --- apps/openmw/mwgui/container.cpp | 8 ++++---- apps/openmw/mwgui/tradewindow.cpp | 16 ++++++++++------ apps/openmw/mwgui/tradewindow.hpp | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 20bc95445..479a82efa 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -195,13 +195,13 @@ void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) if (isInventory()) { MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true); MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } else { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } @@ -218,13 +218,13 @@ void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) if (isInventory()) { MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false); MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } else { MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false); MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index a005c618f..51eb3d87e 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -401,19 +401,23 @@ namespace MWGui return items; } - void TradeWindow::sellToNpc(MWWorld::Ptr item, int count) + void TradeWindow::sellToNpc(MWWorld::Ptr item, int count, bool boughtItem) { + int diff = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count, boughtItem); + + mCurrentBalance += diff; + mCurrentMerchantOffer += diff; - mCurrentBalance -= MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count,true); - mCurrentMerchantOffer -= MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count,true); updateLabels(); } - void TradeWindow::buyFromNpc(MWWorld::Ptr item, int count) + void TradeWindow::buyFromNpc(MWWorld::Ptr item, int count, bool soldItem) { + int diff = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count, !soldItem); + + mCurrentBalance -= diff; + mCurrentMerchantOffer -= diff; - mCurrentBalance += MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count,false); - mCurrentMerchantOffer += MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, MWWorld::Class::get(item).getValue(item) * count,false); updateLabels(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index db386d8b6..219e44036 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -27,8 +27,8 @@ namespace MWGui void startTrade(MWWorld::Ptr actor); - void sellToNpc(MWWorld::Ptr item, int count); ///< only used for adjusting the gold balance - void buyFromNpc(MWWorld::Ptr item, int count); ///< only used for adjusting the gold balance + void sellToNpc(MWWorld::Ptr item, int count, bool boughtItem); ///< only used for adjusting the gold balance + void buyFromNpc(MWWorld::Ptr item, int count, bool soldItem); ///< only used for adjusting the gold balance bool npcAcceptsItem(MWWorld::Ptr item); From ddbe13e5694230b889a6d5606cc36e3a3098b1c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jan 2013 01:07:17 +0100 Subject: [PATCH 224/916] Workaround for http://bugs.openmw.org/issues/475 --- apps/openmw/mwinput/inputmanagerimp.cpp | 9 ++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6a1c3aa9b..995da8f34 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -40,6 +40,7 @@ namespace MWInput , mMouseLookEnabled(true) , mMouseX(ogre.getWindow()->getWidth ()/2.f) , mMouseY(ogre.getWindow()->getHeight ()/2.f) + , mMouseWheel(0) , mUserFile(userFile) , mDragDrop(false) , mGuiCursorEnabled(false) @@ -242,6 +243,11 @@ namespace MWInput mKeyboard->capture(); mMouse->capture(); + // inject some fake mouse movement to force updating MyGUI's widget states + // this shouldn't do any harm since we're moving back to the original position afterwards + MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX+1), int(mMouseY+1), mMouseWheel); + MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); + // update values of channels (as a result of pressed keys) if (!loading) mInputCtrl->update(dt); @@ -486,8 +492,9 @@ namespace MWInput mMouseY += float(arg.state.Y.rel) * mUISensitivity * mUIYMultiplier; mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + mMouseWheel = arg.state.Z.abs; - MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), arg.state.Z.abs); + MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); } if (mMouseLookEnabled) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 718d6b76f..9deed1f28 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -147,6 +147,7 @@ namespace MWInput float mMouseX; float mMouseY; + int mMouseWheel; std::map mControlSwitch; From 1718d735b566786809de51803f308176d3e594a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jan 2013 01:09:03 +0100 Subject: [PATCH 225/916] Fix menu/journal/book/scroll buttons when using localised MW-installations This patch implements a custom widget that can switch its texture on-the-fly, making it obsolete having to use an atlas to get a hover animation. This also removes the predefined size restriction and should now work with all button texture sizes. --- CMakeLists.txt | 1 - apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/bookwindow.cpp | 8 +- apps/openmw/mwgui/bookwindow.hpp | 18 ++-- apps/openmw/mwgui/cursorreplace.cpp | 4 - apps/openmw/mwgui/imagebutton.cpp | 63 ++++++++++++++ apps/openmw/mwgui/imagebutton.hpp | 33 ++++++++ apps/openmw/mwgui/journalwindow.cpp | 5 +- apps/openmw/mwgui/journalwindow.hpp | 14 ++- apps/openmw/mwgui/mainmenu.cpp | 84 +++++++++--------- apps/openmw/mwgui/mainmenu.hpp | 16 ++-- apps/openmw/mwgui/scrollwindow.hpp | 5 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 + files/mygui/CMakeLists.txt | 2 - files/mygui/atlas1.cfg | 51 ----------- files/mygui/mainmenu.cfg | 95 --------------------- files/mygui/openmw_book.layout | 24 ++++-- files/mygui/openmw_journal.layout | 12 ++- files/mygui/openmw_mainmenu_skin.xml | 30 ------- files/mygui/openmw_scroll.layout | 12 ++- libs/openengine/ogre/atlas.cpp | 113 ------------------------- libs/openengine/ogre/atlas.hpp | 27 ------ 22 files changed, 198 insertions(+), 423 deletions(-) create mode 100644 apps/openmw/mwgui/imagebutton.cpp create mode 100644 apps/openmw/mwgui/imagebutton.hpp delete mode 100644 files/mygui/atlas1.cfg delete mode 100644 files/mygui/mainmenu.cfg delete mode 100644 libs/openengine/ogre/atlas.cpp delete mode 100644 libs/openengine/ogre/atlas.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d7115583f..36e45d78a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,6 @@ set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/imagerotate.cpp - ${LIBDIR}/openengine/ogre/atlas.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e2a2e7f14..56147b500 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -30,7 +30,7 @@ add_openmw_dir (mwgui formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog trainingwindow travelwindow + enchantingdialog trainingwindow travelwindow imagebutton ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index bc3cd7b40..659795e18 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -88,7 +88,7 @@ void BookWindow::setTakeButtonShow(bool show) mTakeButton->setVisible(show); } -void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) +void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); @@ -96,7 +96,7 @@ void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) mWindowManager.removeGuiMode(GM_Book); } -void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) +void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) { MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); @@ -106,7 +106,7 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) mWindowManager.removeGuiMode(GM_Book); } -void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender) +void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) { if ((mCurrentPage+1)*2 < mPages.size()) { @@ -118,7 +118,7 @@ void BookWindow::onNextPageButtonClicked (MyGUI::Widget* _sender) } } -void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* _sender) +void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender) { if (mCurrentPage > 0) { diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index fedb783b2..5887975ea 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -5,6 +5,8 @@ #include "../mwworld/ptr.hpp" +#include "imagebutton.hpp" + namespace MWGui { class BookWindow : public WindowBase @@ -16,19 +18,19 @@ namespace MWGui void setTakeButtonShow(bool show); protected: - void onNextPageButtonClicked (MyGUI::Widget* _sender); - void onPrevPageButtonClicked (MyGUI::Widget* _sender); - void onCloseButtonClicked (MyGUI::Widget* _sender); - void onTakeButtonClicked (MyGUI::Widget* _sender); + void onNextPageButtonClicked (MyGUI::Widget* sender); + void onPrevPageButtonClicked (MyGUI::Widget* sender); + void onCloseButtonClicked (MyGUI::Widget* sender); + void onTakeButtonClicked (MyGUI::Widget* sender); void updatePages(); void clearPages(); private: - MyGUI::Button* mCloseButton; - MyGUI::Button* mTakeButton; - MyGUI::Button* mNextPageButton; - MyGUI::Button* mPrevPageButton; + MWGui::ImageButton* mCloseButton; + MWGui::ImageButton* mTakeButton; + MWGui::ImageButton* mNextPageButton; + MWGui::ImageButton* mPrevPageButton; MyGUI::TextBox* mLeftPageNumber; MyGUI::TextBox* mRightPageNumber; MyGUI::Widget* mLeftPage; diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp index a4b6a100b..2079538fc 100644 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ b/apps/openmw/mwgui/cursorreplace.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -14,7 +13,4 @@ CursorReplace::CursorReplace() OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45); OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45); - - OEngine::Render::Atlas::createFromFile("atlas1.cfg", "mwgui1", "textures\\"); - OEngine::Render::Atlas::createFromFile("mainmenu.cfg", "mwgui2", "textures\\"); } diff --git a/apps/openmw/mwgui/imagebutton.cpp b/apps/openmw/mwgui/imagebutton.cpp new file mode 100644 index 000000000..98f05373b --- /dev/null +++ b/apps/openmw/mwgui/imagebutton.cpp @@ -0,0 +1,63 @@ +#include "imagebutton.hpp" + +#include + +namespace MWGui +{ + + void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value) + { + if (_key == "ImageHighlighted") + mImageHighlighted = _value; + else if (_key == "ImagePushed") + mImagePushed = _value; + else if (_key == "ImageNormal") + { + if (mImageNormal == "") + { + setImageTexture(_value); + } + mImageNormal = _value; + } + else + ImageBox::setPropertyOverride(_key, _value); + } + void ImageButton::onMouseSetFocus(Widget* _old) + { + setImageTexture(mImageHighlighted); + ImageBox::onMouseSetFocus(_old); + } + + void ImageButton::onMouseLostFocus(Widget* _new) + { + setImageTexture(mImageNormal); + ImageBox::onMouseLostFocus(_new); + } + + void ImageButton::onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id) + { + if (_id == MyGUI::MouseButton::Left) + setImageTexture(mImagePushed); + + ImageBox::onMouseButtonPressed(_left, _top, _id); + } + + MyGUI::IntSize ImageButton::getRequestedSize() + { + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName(mImageNormal); + if (texture.isNull()) + { + std::cerr << "ImageButton: can't find " << mImageNormal << std::endl; + return MyGUI::IntSize(0,0); + } + return MyGUI::IntSize (texture->getWidth(), texture->getHeight()); + } + + void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) + { + if (_id == MyGUI::MouseButton::Left) + setImageTexture(mImageHighlighted); + + ImageBox::onMouseButtonReleased(_left, _top, _id); + } +} diff --git a/apps/openmw/mwgui/imagebutton.hpp b/apps/openmw/mwgui/imagebutton.hpp new file mode 100644 index 000000000..9fce12da1 --- /dev/null +++ b/apps/openmw/mwgui/imagebutton.hpp @@ -0,0 +1,33 @@ +#ifndef MWGUI_IMAGEBUTTON_H +#define MWGUI_IMAGEBUTTON_H + +#include "MyGUI_ImageBox.h" + +namespace MWGui +{ + + /** + * @brief allows using different image textures depending on the button state + */ + class ImageButton : public MyGUI::ImageBox + { + MYGUI_RTTI_DERIVED(ImageButton) + + public: + MyGUI::IntSize getRequestedSize(); + + protected: + virtual void setPropertyOverride(const std::string& _key, const std::string& _value); + virtual void onMouseLostFocus(MyGUI::Widget* _new); + virtual void onMouseSetFocus(MyGUI::Widget* _old); + virtual void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id); + virtual void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id); + + std::string mImageHighlighted; + std::string mImageNormal; + std::string mImagePushed; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index bbd3d4d28..ba39b0101 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -83,7 +83,6 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) : WindowBase("openmw_journal.layout", parWindowManager) - , mLastPos(0) , mPageNumber(0) { mMainWidget->setVisible(false); @@ -177,7 +176,7 @@ void MWGui::JournalWindow::displayRightText(std::string text) } -void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender) +void MWGui::JournalWindow::notifyNextPage(MyGUI::Widget* _sender) { if(mPageNumber < int(mLeftPages.size())-1) { @@ -189,7 +188,7 @@ void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender) } } -void MWGui::JournalWindow::notifyPrevPage(MyGUI::WidgetPtr _sender) +void MWGui::JournalWindow::notifyPrevPage(MyGUI::Widget* _sender) { if(mPageNumber > 0) { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 3317880cd..044a2b2a4 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -7,6 +7,7 @@ #include #include "window_base.hpp" +#include "imagebutton.hpp" namespace MWGui { @@ -25,18 +26,13 @@ namespace MWGui /** *Called when next/prev button is used. */ - void notifyNextPage(MyGUI::WidgetPtr _sender); - void notifyPrevPage(MyGUI::WidgetPtr _sender); + void notifyNextPage(MyGUI::Widget* _sender); + void notifyPrevPage(MyGUI::Widget* _sender); - static const int sLineHeight; - - MyGUI::WidgetPtr mSkillAreaWidget, mSkillClientWidget; - MyGUI::ScrollBar* mSkillScrollerWidget; - int mLastPos, mClientHeight; MyGUI::EditPtr mLeftTextWidget; MyGUI::EditPtr mRightTextWidget; - MyGUI::ButtonPtr mPrevBtn; - MyGUI::ButtonPtr mNextBtn; + MWGui::ImageButton* mPrevBtn; + MWGui::ImageButton* mNextBtn; std::vector mLeftPages; std::vector mRightPages; int mPageNumber; //store the number of the current left page diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index e98b75e9b..14309abc5 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -20,65 +20,57 @@ namespace MWGui { setCoord(0,0,w,h); - int height = 64 * 3; if (mButtonBox) MyGUI::Gui::getInstance ().destroyWidget(mButtonBox); - mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(w/2 - 64, h/2 - height/2, 128, height), MyGUI::Align::Default); + mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default); int curH = 0; - mReturn = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); - mReturn->setImageResource ("Menu_Return"); - mReturn->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::returnToGame); - curH += 64; + std::vector buttons; + buttons.push_back("return"); + //buttons.push_back("newgame"); + //buttons.push_back("loadgame"); + //buttons.push_back("savegame"); + buttons.push_back("options"); + //buttons.push_back("credits"); + buttons.push_back("exitgame"); + int maxwidth = 0; - /* - mNewGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); - mNewGame->setImageResource ("Menu_NewGame"); - curH += 64; + mButtons.clear(); + for (std::vector::iterator it = buttons.begin(); it != buttons.end(); ++it) + { + MWGui::ImageButton* button = mButtonBox->createWidget + ("ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default); + button->setProperty("ImageHighlighted", "textures\\menu_" + *it + "_over.dds"); + button->setProperty("ImageNormal", "textures\\menu_" + *it + ".dds"); + button->setProperty("ImagePushed", "textures\\menu_" + *it + "_pressed.dds"); + MyGUI::IntSize requested = button->getRequestedSize(); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked); + mButtons[*it] = button; + curH += requested.height; - mLoadGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); - mLoadGame->setImageResource ("Menu_LoadGame"); - curH += 64; + if (requested.width > maxwidth) + maxwidth = requested.width; + } + for (std::map::iterator it = mButtons.begin(); it != mButtons.end(); ++it) + { + MyGUI::IntSize requested = it->second->getRequestedSize(); + it->second->setCoord((maxwidth-requested.width) / 2, it->second->getTop(), requested.width, requested.height); + } - - mSaveGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); - mSaveGame->setImageResource ("Menu_SaveGame"); - curH += 64; - */ - - mOptions = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); - mOptions->setImageResource ("Menu_Options"); - mOptions->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::showOptions); - curH += 64; - - /* - mCredits = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); - mCredits->setImageResource ("Menu_Credits"); - curH += 64; - */ - - mExitGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); - mExitGame->setImageResource ("Menu_ExitGame"); - mExitGame->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::exitGame); - curH += 64; + mButtonBox->setCoord (w/2 - maxwidth/2, h/2 - curH/2, maxwidth, curH); } - void MainMenu::returnToGame(MyGUI::Widget* sender) + void MainMenu::onButtonClicked(MyGUI::Widget *sender) { - MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); - } - - void MainMenu::showOptions(MyGUI::Widget* sender) - { - MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings); - } - - void MainMenu::exitGame(MyGUI::Widget* sender) - { - Ogre::Root::getSingleton ().queueEndRendering (); + if (sender == mButtons["return"]) + MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); + else if (sender == mButtons["options"]) + MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings); + else if (sender == mButtons["exitgame"]) + Ogre::Root::getSingleton ().queueEndRendering (); } } diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index fd583d187..4e76a64df 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -1,5 +1,7 @@ #include +#include "imagebutton.hpp" + namespace MWGui { @@ -11,19 +13,11 @@ namespace MWGui void onResChange(int w, int h); private: - MyGUI::Button* mReturn; - MyGUI::Button* mNewGame; - MyGUI::Button* mLoadGame; - MyGUI::Button* mSaveGame; - MyGUI::Button* mOptions; - MyGUI::Button* mCredits; - MyGUI::Button* mExitGame; - MyGUI::Widget* mButtonBox; - void returnToGame(MyGUI::Widget* sender); - void showOptions(MyGUI::Widget* sender); - void exitGame(MyGUI::Widget* sender); + std::map mButtons; + + void onButtonClicked (MyGUI::Widget* sender); }; } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index b8f52fb65..7932a215b 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -2,6 +2,7 @@ #define MWGUI_SCROLLWINDOW_H #include "window_base.hpp" +#include "imagebutton.hpp" #include "../mwworld/ptr.hpp" @@ -20,8 +21,8 @@ namespace MWGui void onTakeButtonClicked (MyGUI::Widget* _sender); private: - MyGUI::Button* mCloseButton; - MyGUI::Button* mTakeButton; + MWGui::ImageButton* mCloseButton; + MWGui::ImageButton* mTakeButton; MyGUI::ScrollView* mTextView; MWWorld::Ptr mScroll; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7f5d34939..099dafa6b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -51,6 +51,7 @@ #include "spellcreationdialog.hpp" #include "enchantingdialog.hpp" #include "trainingwindow.hpp" +#include "imagebutton.hpp" using namespace MWGui; @@ -126,6 +127,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 562668a90..871be93d1 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -4,8 +4,6 @@ set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) set(MYGUI_FILES - atlas1.cfg - mainmenu.cfg bigbars.png black.png core.skin diff --git a/files/mygui/atlas1.cfg b/files/mygui/atlas1.cfg deleted file mode 100644 index d1e05e041..000000000 --- a/files/mygui/atlas1.cfg +++ /dev/null @@ -1,51 +0,0 @@ -[settings] - size_x = 512 - size_y = 512 - -[tx_menubook_close_idle.dds] - x = 0 - y = 0 - -[tx_menubook_close_over.dds] - x = 128 - y = 0 - -[tx_menubook_close_pressed.dds] - x = 256 - y = 0 - -[tx_menubook_take_idle.dds] - x = 384 - y = 0 - -[tx_menubook_take_over.dds] - x = 0 - y = 32 - -[tx_menubook_take_pressed.dds] - x = 128 - y = 32 - -[tx_menubook_next_idle.dds] - x = 256 - y = 32 - -[tx_menubook_next_over.dds] - x = 384 - y = 32 - -[tx_menubook_next_pressed.dds] - x = 0 - y = 64 - -[tx_menubook_prev_idle.dds] - x = 128 - y = 64 - -[tx_menubook_prev_over.dds] - x = 256 - y = 64 - -[tx_menubook_prev_pressed.dds] - x = 384 - y = 64 diff --git a/files/mygui/mainmenu.cfg b/files/mygui/mainmenu.cfg deleted file mode 100644 index 7aaf8c1c7..000000000 --- a/files/mygui/mainmenu.cfg +++ /dev/null @@ -1,95 +0,0 @@ -[settings] - size_x = 512 - size_y = 512 - - -[menu_newgame.dds] - x = 0 - y = 0 - -[menu_newgame_pressed.dds] - x = 128 - y = 0 - -[menu_newgame_over.dds] - x = 256 - y = 0 - - -[menu_loadgame.dds] - x = 384 - y = 0 - -[menu_loadgame_pressed.dds] - x = 0 - y = 64 - -[menu_loadgame_over.dds] - x = 128 - y = 64 - - -[menu_options.dds] - x = 256 - y = 64 - -[menu_options_pressed.dds] - x = 384 - y = 64 - -[menu_options_over.dds] - x = 0 - y = 128 - - -[menu_credits.dds] - x = 128 - y = 128 - -[menu_credits_pressed.dds] - x = 256 - y = 128 - -[menu_credits_over.dds] - x = 384 - y = 128 - - -[menu_exitgame.dds] - x = 0 - y = 192 - -[menu_exitgame_pressed.dds] - x = 128 - y = 192 - -[menu_exitgame_over.dds] - x = 256 - y = 192 - - -[menu_savegame.dds] - x = 384 - y = 192 - -[menu_savegame_pressed.dds] - x = 0 - y = 256 - -[menu_savegame_over.dds] - x = 128 - y = 256 - - -[menu_return.dds] - x = 256 - y = 256 - -[menu_return_pressed.dds] - x = 384 - y = 256 - -[menu_return_over.dds] - x = 0 - y = 320 - diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 6c708cdd3..894c1dbeb 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -7,17 +7,25 @@ - - + + + + - - + + + + - - + + + + - - + + + + diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index e4c3c7e47..fdf82e4de 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -7,11 +7,15 @@ - - + + + + - - + + + + diff --git a/files/mygui/openmw_mainmenu_skin.xml b/files/mygui/openmw_mainmenu_skin.xml index 4100a2eb7..c7f2fbce3 100644 --- a/files/mygui/openmw_mainmenu_skin.xml +++ b/files/mygui/openmw_mainmenu_skin.xml @@ -1,34 +1,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/mygui/openmw_scroll.layout b/files/mygui/openmw_scroll.layout index 0f4a0be3e..6315c0241 100644 --- a/files/mygui/openmw_scroll.layout +++ b/files/mygui/openmw_scroll.layout @@ -7,12 +7,16 @@ - - + + + + - - + + + + diff --git a/libs/openengine/ogre/atlas.cpp b/libs/openengine/ogre/atlas.cpp deleted file mode 100644 index 01b84afab..000000000 --- a/libs/openengine/ogre/atlas.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "atlas.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Ogre; -using namespace OEngine::Render; - -void Atlas::createFromFile (const std::string& filename, const std::string& textureName, const std::string& texturePrefix) -{ - ConfigFile file; - file.load(filename, ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, "\t:=", true); - - Root* root = Ogre::Root::getSingletonPtr(); - - SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); - Camera* camera = sceneMgr->createCamera("AtlasCamera"); - - int width = StringConverter::parseInt(file.getSetting("size_x", "settings")); - int height = StringConverter::parseInt(file.getSetting("size_y", "settings")); - - std::vector rectangles; - int i = 0; - - ConfigFile::SectionIterator seci = file.getSectionIterator(); - while (seci.hasMoreElements()) - { - Ogre::String sectionName = seci.peekNextKey(); - seci.getNext(); - - if (sectionName == "settings" || sectionName == "") - continue; - - MaterialPtr material = MaterialManager::getSingleton().create("AtlasMaterial" + StringConverter::toString(i), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - material->getTechnique(0)->getPass(0)->setLightingEnabled(false); - material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(texturePrefix + sectionName); - tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); - - Rectangle2D* rect = new Rectangle2D(true); - rect->setMaterial("AtlasMaterial" + StringConverter::toString(i)); - rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); - - int x = StringConverter::parseInt(file.getSetting("x", sectionName)); - int y = StringConverter::parseInt(file.getSetting("y", sectionName)); - - TexturePtr texture = TextureManager::getSingleton().getByName(texturePrefix + sectionName); - if (texture.isNull()) - { - std::cerr << "OEngine::Render::Atlas: Can't find texture " << texturePrefix + sectionName << ", skipping..." << std::endl; - continue; - } - int textureWidth = texture->getWidth(); - int textureHeight = texture->getHeight(); - - float left = x/float(width) * 2 - 1; - float top = (1-(y/float(height))) * 2 - 1; - float right = ((x+textureWidth))/float(width) * 2 - 1; - float bottom = (1-((y+textureHeight)/float(height))) * 2 - 1; - rect->setCorners(left, top, right, bottom); - - // Use infinite AAB to always stay visible - AxisAlignedBox aabInf; - aabInf.setInfinite(); - rect->setBoundingBox(aabInf); - - // Attach background to the scene - SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(rect); - - rectangles.push_back(rect); - ++i; - } - - TexturePtr destTexture = TextureManager::getSingleton().createManual( - textureName, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_FLOAT16_RGBA, - TU_RENDERTARGET); - - RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); - rtt->setAutoUpdated(false); - Viewport* vp = rtt->addViewport(camera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0,0,0,0)); - - rtt->update(); - - // remove all the junk we've created - for (std::vector::iterator it=rectangles.begin(); - it!=rectangles.end(); ++it) - { - delete (*it); - } - while (i > 0) - { - MaterialManager::getSingleton().remove("AtlasMaterial" + StringConverter::toString(i-1)); - --i; - } - root->destroySceneManager(sceneMgr); -} diff --git a/libs/openengine/ogre/atlas.hpp b/libs/openengine/ogre/atlas.hpp deleted file mode 100644 index 5dcd409ca..000000000 --- a/libs/openengine/ogre/atlas.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef OENGINE_OGRE_ATLAS_HPP -#define OENGINE_OGRE_ATLAS_HPP - -#include - -namespace OEngine -{ -namespace Render -{ - - /// \brief Creates a texture atlas at runtime - class Atlas - { - public: - /** - * @param absolute path to file that specifies layout of the texture (positions of the textures it contains) - * @param name of the destination texture to save to (in memory) - * @param texture directory prefix - */ - static void createFromFile (const std::string& filename, const std::string& textureName, const std::string& texturePrefix="textures\\"); - }; - -} -} - -#endif - From ba7086cadf88ecc9aaf15908e2cbc83e7ab8080f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jan 2013 02:05:05 +0100 Subject: [PATCH 226/916] Use race/class names (instead of ID) in replaced escape sequences --- apps/openmw/mwscript/interpretercontext.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index cb0e4a7f9..a8d615d89 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -252,15 +252,17 @@ namespace MWScript std::string InterpreterContext::getPCRace() const { MWBase::World *world = MWBase::Environment::get().getWorld(); - ESM::NPC player = *world->getPlayer().getPlayer().get()->mBase; - return player.mRace; + std::string race = world->getPlayer().getPlayer().get()->mBase->mRace; + const ESM::Race* _race = world->getStore().get().find(race); + return _race->mName; } std::string InterpreterContext::getPCClass() const { MWBase::World *world = MWBase::Environment::get().getWorld(); - ESM::NPC player = *world->getPlayer().getPlayer().get()->mBase; - return player.mClass; + std::string _class = world->getPlayer().getPlayer().get()->mBase->mClass; + const ESM::Class* __class = world->getStore().get().find(_class); + return __class->mName; } std::string InterpreterContext::getPCRank() const From 42e0501c671b2034f5d6f8a7c90dc85f34d1dd51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 3 Jan 2013 02:40:21 +0100 Subject: [PATCH 227/916] fix typo --- apps/openmw/mwscript/docs/vmformat.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 8a0913517..89cacf65c 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -4,7 +4,7 @@ Segment 0: (not implemented yet) opcodes 0x20-0x3f unused -Segment 1:< +Segment 1: (not implemented yet) opcodes 0x20-0x3f unused From 25d9918765e32fd6b4d0aa4f0bd4108d7e4a9e80 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Jan 2013 09:55:48 +0100 Subject: [PATCH 228/916] post merge fix: bringing code more in line with our naming standards and fixing an invalid name (names starting with double underscore are reserved in C++) --- apps/openmw/mwscript/interpretercontext.cpp | 48 ++++++++++----------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index a8d615d89..c74e3f163 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -179,17 +179,17 @@ namespace MWScript std::vector InterpreterContext::getGlobals () const { - MWBase::World *world = MWBase::Environment::get().getWorld(); + MWBase::World *world = MWBase::Environment::get().getWorld(); return world->getGlobals(); } - + char InterpreterContext::getGlobalType (const std::string& name) const { - MWBase::World *world = MWBase::Environment::get().getWorld(); + MWBase::World *world = MWBase::Environment::get().getWorld(); return world->getGlobalVariableType(name); } - + std::string InterpreterContext::getActionBinding(const std::string& action) const { std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); @@ -205,19 +205,19 @@ namespace MWScript return "None"; } - + std::string InterpreterContext::getNPCName() const { ESM::NPC npc = *mReference.get()->mBase; return npc.mName; } - + std::string InterpreterContext::getNPCRace() const { ESM::NPC npc = *mReference.get()->mBase; return npc.mRace; } - + std::string InterpreterContext::getNPCClass() const { ESM::NPC npc = *mReference.get()->mBase; @@ -238,7 +238,7 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::ESMStore &store = world->getStore(); const ESM::Faction *faction = store.get().find(it->first); - + return faction->mRanks[it->second]; } @@ -253,66 +253,64 @@ namespace MWScript { MWBase::World *world = MWBase::Environment::get().getWorld(); std::string race = world->getPlayer().getPlayer().get()->mBase->mRace; - const ESM::Race* _race = world->getStore().get().find(race); - return _race->mName; + return world->getStore().get().find(race)->mName; } std::string InterpreterContext::getPCClass() const { MWBase::World *world = MWBase::Environment::get().getWorld(); - std::string _class = world->getPlayer().getPlayer().get()->mBase->mClass; - const ESM::Class* __class = world->getStore().get().find(_class); - return __class->mName; + std::string class_ = world->getPlayer().getPlayer().get()->mBase->mClass; + return world->getStore().get().find(class_)->mName; } - + std::string InterpreterContext::getPCRank() const { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayer().getPlayer(); - + std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first; - + std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); std::map::const_iterator it = ranks.begin(); const MWWorld::ESMStore &store = world->getStore(); const ESM::Faction *faction = store.get().find(factionId); - + if(it->second < 0 || it->second > 9) // there are only 10 ranks return ""; - + return faction->mRanks[it->second]; - } + } std::string InterpreterContext::getPCNextRank() const { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayer().getPlayer(); - + std::string factionId = MWWorld::Class::get (mReference).getNpcStats (mReference).getFactionRanks().begin()->first; - + std::map ranks = MWWorld::Class::get (player).getNpcStats (player).getFactionRanks(); std::map::const_iterator it = ranks.begin(); const MWWorld::ESMStore &store = world->getStore(); const ESM::Faction *faction = store.get().find(factionId); - + if(it->second < 0 || it->second > 9) return ""; - + if(it->second <= 8) // If player is at max rank, there is no next rank return faction->mRanks[it->second + 1]; else return faction->mRanks[it->second]; } - + int InterpreterContext::getPCBounty() const { MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayer().getPlayer(); return MWWorld::Class::get (player).getNpcStats (player).getBounty(); } - + std::string InterpreterContext::getCurrentCellName() const { MWBase::World *world = MWBase::Environment::get().getWorld(); From 5c007cd52714779c071ef8bf5b82c808090edc8d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Jan 2013 10:05:37 +0100 Subject: [PATCH 229/916] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 713fbe9ac..e1905c88b 100644 --- a/credits.txt +++ b/credits.txt @@ -21,6 +21,7 @@ Cris Mihalache (Mirceam) Douglas Diniz (Dgdiniz) Eduard Cot (trombonecot) Eli2 +Emanuel "potatoesmaster" Guével gugus / gus Jacob Essex (Yacoby) Jannik Heller (scrawl) From b7b51f24d63696436157086ed79356704889d084 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 3 Jan 2013 11:20:25 +0100 Subject: [PATCH 230/916] added new Role for table headers (Role_Display) --- apps/opencs/model/world/columnbase.cpp | 4 ++-- apps/opencs/model/world/columnbase.hpp | 18 ++++++++++++++---- apps/opencs/model/world/columns.hpp | 9 +++++---- apps/opencs/model/world/idtable.cpp | 3 +++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index 7adc7e6c3..134c582c4 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -1,8 +1,8 @@ #include "columnbase.hpp" -CSMWorld::ColumnBase::ColumnBase (const std::string& title, int flags) -: mTitle (title), mFlags (flags) +CSMWorld::ColumnBase::ColumnBase (const std::string& title, Display displayType, int flags) +: mTitle (title), mDisplayType (displayType), mFlags (flags) {} CSMWorld::ColumnBase::~ColumnBase() {} diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index dc077eff6..38b73ee3f 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -14,7 +14,8 @@ namespace CSMWorld { enum Roles { - Role_Flags = Qt::UserRole + Role_Flags = Qt::UserRole, + Role_Display = Qt::UserRole+1 }; enum Flags @@ -23,10 +24,18 @@ namespace CSMWorld Flag_Dialogue = 2 // column should be displayed in dialogue view }; + enum Display + { + Display_String, + Display_Integer, + Display_Float + }; + std::string mTitle; int mFlags; + Display mDisplayType; - ColumnBase (const std::string& title, int flag); + ColumnBase (const std::string& title, Display displayType, int flag); virtual ~ColumnBase(); @@ -34,6 +43,7 @@ namespace CSMWorld virtual bool isUserEditable() const; ///< Can this column be edited directly by the user? + }; template @@ -42,8 +52,8 @@ namespace CSMWorld std::string mTitle; int mFlags; - Column (const std::string& title, int flags = Flag_Table | Flag_Dialogue) - : ColumnBase (title, flags) {} + Column (const std::string& title, Display displayType, int flags = Flag_Table | Flag_Dialogue) + : ColumnBase (title, displayType, flags) {} virtual QVariant get (const Record& record) const = 0; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 5abf4ea8b..1e2de9265 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -8,7 +8,7 @@ namespace CSMWorld template struct FloatValueColumn : public Column { - FloatValueColumn() : Column ("Value") {} + FloatValueColumn() : Column ("Value", ColumnBase::Display_Float) {} virtual QVariant get (const Record& record) const { @@ -31,7 +31,7 @@ namespace CSMWorld template struct StringIdColumn : public Column { - StringIdColumn() : Column ("ID") {} + StringIdColumn() : Column ("ID", ColumnBase::Display_String) {} virtual QVariant get (const Record& record) const { @@ -47,7 +47,7 @@ namespace CSMWorld template struct RecordStateColumn : public Column { - RecordStateColumn() : Column ("*") {} + RecordStateColumn() : Column ("*", ColumnBase::Display_Integer) {} virtual QVariant get (const Record& record) const { @@ -78,7 +78,8 @@ namespace CSMWorld { int mType; - FixedRecordTypeColumn (int type) : Column ("Type", 0), mType (type) {} + FixedRecordTypeColumn (int type) + : Column ("Type", ColumnBase::Display_Integer, 0), mType (type) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 2815e318c..afed6b6ed 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -51,6 +51,9 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation if (role==ColumnBase::Role_Flags) return mIdCollection->getColumn (section).mFlags; + if (role==ColumnBase::Role_Display) + return mIdCollection->getColumn (section).mDisplayType; + return QVariant(); } From d6377fb2e39ef8d25fd887511d7f0bc501f00b59 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Thu, 3 Jan 2013 18:51:04 +0100 Subject: [PATCH 231/916] - Support deleting references from a plugin - Add preliminary support for loading some unique fields appearing only in savegames - Add a few lines required for supporting respawning references. Incomplete. --- apps/openmw/mwworld/cellstore.cpp | 7 +++++-- apps/openmw/mwworld/cellstore.hpp | 7 +++++++ components/esm/esmreader.hpp | 8 ++++++++ components/esm/loadcell.cpp | 28 ++++++++++++++++++++++++++-- components/esm/loadcell.hpp | 3 +++ 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ba8f5aa61..d007ff981 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -61,11 +61,15 @@ namespace MWWorld while (mCell->getNextRef (esm[index], ref)) { std::string lowerCase; + if (ref.mDeleted) { + // Right now, don't do anything. Wehere is "listRefs" actually used, anyway? + // Skipping for now... + continue; + } std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: Fully support deletion of references. mIds.push_back (lowerCase); } } @@ -97,7 +101,6 @@ namespace MWWorld std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - // TODO: Fully support deletion of references. int rec = store.find(ref.mRefID); ref.mRefID = lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cf09496e8..2b25faa70 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -59,6 +59,13 @@ namespace MWWorld /// on miss void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) { + // Skip this when reference was deleted. + // TODO: Support respawning references, in this case, we need to track it somehow. + if (ref.mDeleted) { + mList.erase(ref.mRefnum); + return; + } + // for throwing exception on unhandled record type const MWWorld::Store &store = esmStore.get(); const X *ptr = store.search(ref.mRefID); diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 732dbe9bc..df4c1919e 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -119,6 +119,14 @@ public: getHT(x); } + template + void getHNOT(X &x, const char* name, int size) + { + assert(sizeof(X) == size); + if(isNextSub(name)) + getHT(x); + } + int64_t getHNLong(const char *name); // Get data of a given type/size, including subrecord header diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index b7f27b08d..aafe629e6 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -213,7 +213,24 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // missing ref.mScale = 1.0; esm.getHNOT(ref.mScale, "XSCL"); - + + // TODO: support loading references from saves, there are tons of keys not recognized yet. + // The following is just an incomplete list. + if (esm.isNextSub("ACTN")) + esm.skipHSub(); + if (esm.isNextSub("STPR")) + esm.skipHSub(); + if (esm.isNextSub("ACDT")) + esm.skipHSub(); + if (esm.isNextSub("ACSC")) + esm.skipHSub(); + if (esm.isNextSub("ACSL")) + esm.skipHSub(); + if (esm.isNextSub("CHRD")) + esm.skipHSub(); + else if (esm.isNextSub("CRED")) // ??? + esm.skipHSub(); + ref.mOwner = esm.getHNOString("ANAM"); ref.mGlob = esm.getHNOString("BNAM"); ref.mSoul = esm.getHNOString("XSOL"); @@ -251,7 +268,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNOT(ref.mUnam, "UNAM"); esm.getHNOT(ref.mFltv, "FLTV"); - esm.getHNT(ref.mPos, "DATA", 24); + esm.getHNOT(ref.mPos, "DATA", 24); // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other @@ -265,6 +282,13 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHT(ref.mNam0); //esm.getHNOT(NAM0, "NAM0"); } + + if (esm.isNextSub("DELE")) { + esm.skipHSub(); + ref.mDeleted = 2; // Deleted, will not respawn. + // TODO: find out when references do respawn. + } else + ref.mDeleted = 0; return true; } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index ccfdcadd8..dff5a3338 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -70,6 +70,9 @@ public: // No idea - occurs ONCE in Morrowind.esm, for an activator char mUnam; + + // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. + int mDeleted; // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza // Brindisi Dorom", where it has the value 100. Also only for From 9afe4467d8e5ea3f6fc9960e338bc16bcc1d7bbc Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Wed, 2 Jan 2013 13:50:44 -0800 Subject: [PATCH 232/916] cache results of query for spash screen names ResourceGroupManager::listResourceNames returns a list of all resource accessable which is expensive, this change caches the result of the processed query so additional splash screen changes are quicker. --- apps/openmw/mwgui/loadingscreen.cpp | 28 ++++++++++++++++------------ apps/openmw/mwgui/loadingscreen.hpp | 1 + 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index d721e209a..a508bcd34 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -213,22 +213,26 @@ namespace MWGui void LoadingScreen::changeWallpaper () { - std::vector splash; - - Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false); - for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it) + if (mResources.isNull ()) { - if (it->size() < 6) - continue; - std::string start = it->substr(0, 6); - boost::to_lower(start); + mResources = Ogre::StringVectorPtr (new Ogre::StringVector); - if (start == "splash") - splash.push_back (*it); + Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false); + for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it) + { + if (it->size() < 6) + continue; + std::string start = it->substr(0, 6); + boost::to_lower(start); + + if (start == "splash") + mResources->push_back (*it); + } } - if (splash.size()) + + if (mResources->size()) { - std::string randomSplash = splash[rand() % splash.size()]; + std::string randomSplash = mResources->at (rand() % mResources->size()); Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); mBackgroundImage->setImageTexture (randomSplash); diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index a012793ca..c14087a3b 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -42,6 +42,7 @@ namespace MWGui Ogre::Rectangle2D* mRectangle; Ogre::MaterialPtr mBackgroundMaterial; + Ogre::StringVectorPtr mResources; bool mLoadingOn; From 740e2b5769d85bec22b8478846bd3800d2552049 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 2 Jan 2013 23:02:13 +0100 Subject: [PATCH 233/916] components/to_utf8: add class Utf8Encoder --- components/to_utf8/to_utf8.cpp | 743 +++++++++++++++++++++++---------- components/to_utf8/to_utf8.hpp | 67 ++- 2 files changed, 563 insertions(+), 247 deletions(-) diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 7db611247..8ac582b81 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include /* This file contains the code to translate from WINDOWS-1252 (native charset used in English version of Morrowind) to UTF-8. The library @@ -46,334 +48,611 @@ static std::vector buf (50*1024); static std::vector output (50*1024); static int size; -// Make sure the given vector is large enough for 'size' bytes, +using namespace ToUTF8; + +Utf8Encoder::Utf8Encoder(void): + mOutput(50*1024) +{ +} + +void Utf8Encoder::setEncoding(const FromType sourceEncoding) +{ + mEncoding = sourceEncoding; + + switch (mEncoding) + { + case ToUTF8::WINDOWS_1252: + { + translationArray = ToUTF8::windows_1252; + break; + } + case ToUTF8::WINDOWS_1250: + { + translationArray = ToUTF8::windows_1250; + break; + } + case ToUTF8::WINDOWS_1251: + { + translationArray = ToUTF8::windows_1251; + break; + } + default: + { + assert(0); + } + } +} + +std::string Utf8Encoder::getUtf8(const char* input, int size) +{ + // Double check that the input string stops at some point (it might + // contain zero terminators before this, inside its own data, which + // is also ok.) + assert(input[size] == 0); + + // TODO: The rest of this function is designed for single-character + // input encodings only. It also assumes that the input the input + // encoding shares its first 128 values (0-127) with ASCII. These + // conditions must be checked again if you add more input encodings + // later. + + // Compute output length, and check for pure ascii input at the same + // time. + bool ascii; + size_t outlen = getLength(input, ascii); + + // If we're pure ascii, then don't bother converting anything. + if(ascii) + return std::string(input, outlen); + + // Make sure the output is large enough + resize(outlen); + char *out = &mOutput[0]; + + // Translate + while (*input) + copyFromArray(*(input++), out); + + // Make sure that we wrote the correct number of bytes + assert((out-&mOutput[0]) == (int)outlen); + + // And make extra sure the output is null terminated + assert(mOutput.size() > outlen); + assert(mOutput[outlen] == 0); + + // Return a string + return std::string(&mOutput[0], outlen); +} + +std::string Utf8Encoder::getLegacyEnc(const char *input, int size) +{ + // Double check that the input string stops at some point (it might + // contain zero terminators before this, inside its own data, which + // is also ok.) + assert(input[size] == 0); + + // TODO: The rest of this function is designed for single-character + // input encodings only. It also assumes that the input the input + // encoding shares its first 128 values (0-127) with ASCII. These + // conditions must be checked again if you add more input encodings + // later. + + // Compute output length, and check for pure ascii input at the same + // time. + bool ascii; + size_t outlen = getLength2(input, ascii); + + // If we're pure ascii, then don't bother converting anything. + if(ascii) + return std::string(input, outlen); + + // Make sure the output is large enough + resize(outlen); + char *out = &mOutput[0]; + + // Translate + while(*input) + copyFromArray2(input, out); + + // Make sure that we wrote the correct number of bytes + assert((out-&mOutput[0]) == (int)outlen); + + // And make extra sure the output is null terminated + assert(mOutput.size() > outlen); + assert(mOutput[outlen] == 0); + + // Return a string + return std::string(&mOutput[0], outlen); +} + +// Make sure the output vector is large enough for 'size' bytes, // including a terminating zero after it. +void Utf8Encoder::resize(size_t size) +{ + if (mOutput.size() <= size) + // Add some extra padding to reduce the chance of having to resize + // again later. + mOutput.resize(3*size); + + // And make sure the string is zero terminated + mOutput[size] = 0; +} + +/** Get the total length length needed to decode the given string with + the given translation array. The arrays are encoded with 6 bytes + per character, with the first giving the length and the next 5 the + actual data. + + The function serves a dual purpose for optimization reasons: it + checks if the input is pure ascii (all values are <= 127). If this + is the case, then the ascii parameter is set to true, and the + caller can optimize for this case. + */ +size_t Utf8Encoder::getLength(const char* input, bool &ascii) +{ + ascii = true; + size_t len = 0; + const char* ptr = input; + unsigned char inp = *ptr; + + // Do away with the ascii part of the string first (this is almost + // always the entire string.) + while (inp && inp < 128) + inp = *(++ptr); + len += (ptr-input); + + // If we're not at the null terminator at this point, then there + // were some non-ascii characters to deal with. Go to slow-mode for + // the rest of the string. + if (inp) + { + ascii = false; + while (inp) + { + // Find the translated length of this character in the + // lookup table. + len += translationArray[inp*6]; + inp = *(++ptr); + } + } + return len; +} + +// Translate one character 'ch' using the translation array 'arr', and +// advance the output pointer accordingly. +void Utf8Encoder::copyFromArray(unsigned char ch, char* &out) +{ + // Optimize for ASCII values + if (ch < 128) + { + *(out++) = ch; + return; + } + + const char *in = translationArray + ch*6; + int len = *(in++); + for (int i=0; i &buf, size_t size) { - if(buf.size() <= size) - // Add some extra padding to reduce the chance of having to resize - // again later. - buf.resize(3*size); + if(buf.size() <= size) + // Add some extra padding to reduce the chance of having to resize + // again later. + buf.resize(3*size); - // And make sure the string is zero terminated - buf[size] = 0; + // And make sure the string is zero terminated + buf[size] = 0; } // This is just used to spew out a reusable input buffer for the // conversion process. char *ToUTF8::getBuffer(int s) { - // Remember the requested size - size = s; - resize(buf, size); - return &buf[0]; + // Remember the requested size + size = s; + resize(buf, size); + return &buf[0]; } /** Get the total length length needed to decode the given string with - the given translation array. The arrays are encoded with 6 bytes - per character, with the first giving the length and the next 5 the - actual data. + the given translation array. The arrays are encoded with 6 bytes + per character, with the first giving the length and the next 5 the + actual data. - The function serves a dual purpose for optimization reasons: it - checks if the input is pure ascii (all values are <= 127). If this - is the case, then the ascii parameter is set to true, and the - caller can optimize for this case. + The function serves a dual purpose for optimization reasons: it + checks if the input is pure ascii (all values are <= 127). If this + is the case, then the ascii parameter is set to true, and the + caller can optimize for this case. */ static size_t getLength(const char *arr, const char* input, bool &ascii) { - ascii = true; - size_t len = 0; - const char* ptr = input; - unsigned char inp = *ptr; + ascii = true; + size_t len = 0; + const char* ptr = input; + unsigned char inp = *ptr; - // Do away with the ascii part of the string first (this is almost - // always the entire string.) - while(inp && inp < 128) - inp = *(++ptr); - len += (ptr-input); + // Do away with the ascii part of the string first (this is almost + // always the entire string.) + while(inp && inp < 128) + inp = *(++ptr); + len += (ptr-input); - // If we're not at the null terminator at this point, then there - // were some non-ascii characters to deal with. Go to slow-mode for - // the rest of the string. - if(inp) + // If we're not at the null terminator at this point, then there + // were some non-ascii characters to deal with. Go to slow-mode for + // the rest of the string. + if(inp) { - ascii = false; - while(inp) + ascii = false; + while(inp) { - // Find the translated length of this character in the - // lookup table. - len += arr[inp*6]; - inp = *(++ptr); + // Find the translated length of this character in the + // lookup table. + len += arr[inp*6]; + inp = *(++ptr); } } - return len; + return len; } // Translate one character 'ch' using the translation array 'arr', and // advance the output pointer accordingly. static void copyFromArray(const char *arr, unsigned char ch, char* &out) { - // Optimize for ASCII values - if(ch < 128) + // Optimize for ASCII values + if(ch < 128) { - *(out++) = ch; - return; + *(out++) = ch; + return; } - const char *in = arr + ch*6; - int len = *(in++); - for(int i=0; i outlen); - assert(output[outlen] == 0); + // And make extra sure the output is null terminated + assert(output.size() > outlen); + assert(output[outlen] == 0); - // Return a string - return std::string(&output[0], outlen); + // Return a string + return std::string(&output[0], outlen); } static size_t getLength2(const char *arr, const char* input, bool &ascii) { - ascii = true; - size_t len = 0; - const char* ptr = input; - unsigned char inp = *ptr; + ascii = true; + size_t len = 0; + const char* ptr = input; + unsigned char inp = *ptr; - // Do away with the ascii part of the string first (this is almost - // always the entire string.) - while(inp && inp < 128) - inp = *(++ptr); - len += (ptr-input); + // Do away with the ascii part of the string first (this is almost + // always the entire string.) + while(inp && inp < 128) + inp = *(++ptr); + len += (ptr-input); - // If we're not at the null terminator at this point, then there - // were some non-ascii characters to deal with. Go to slow-mode for - // the rest of the string. - if(inp) + // If we're not at the null terminator at this point, then there + // were some non-ascii characters to deal with. Go to slow-mode for + // the rest of the string. + if(inp) { - ascii = false; - while(inp) + ascii = false; + while(inp) { len += 1; - // Find the translated length of this character in the - // lookup table. + // Find the translated length of this character in the + // lookup table. switch(inp) { - case 0xe2: len -= 2; break; - case 0xc2: - case 0xcb: - case 0xc4: - case 0xc6: - case 0xc3: - case 0xd0: - case 0xd1: - case 0xd2: - case 0xc5: len -= 1; break; + case 0xe2: len -= 2; break; + case 0xc2: + case 0xcb: + case 0xc4: + case 0xc6: + case 0xc3: + case 0xd0: + case 0xd1: + case 0xd2: + case 0xc5: len -= 1; break; } - inp = *(++ptr); + inp = *(++ptr); } } - return len; + return len; } -#include -#include - static void copyFromArray2(const char *arr, char*& chp, char* &out) { unsigned char ch = *(chp++); - // Optimize for ASCII values - if(ch < 128) + // Optimize for ASCII values + if(ch < 128) { - *(out++) = ch; - return; + *(out++) = ch; + return; } - int len = 1; - switch (ch) - { - case 0xe2: len = 3; break; - case 0xc2: - case 0xcb: - case 0xc4: - case 0xc6: - case 0xc3: - case 0xd0: - case 0xd1: - case 0xd2: - case 0xc5: len = 2; break; - } + int len = 1; + switch (ch) + { + case 0xe2: len = 3; break; + case 0xc2: + case 0xcb: + case 0xc4: + case 0xc6: + case 0xc3: + case 0xd0: + case 0xd1: + case 0xd2: + case 0xc5: len = 2; break; + } - if (len == 1) // There is no 1 length utf-8 glyph that is not 0x20 (empty space) - { - *(out++) = ch; - return; - } + if (len == 1) // There is no 1 length utf-8 glyph that is not 0x20 (empty space) + { + *(out++) = ch; + return; + } - unsigned char ch2 = *(chp++); - unsigned char ch3 = '\0'; - if (len == 3) - ch3 = *(chp++); + unsigned char ch2 = *(chp++); + unsigned char ch3 = '\0'; + if (len == 3) + ch3 = *(chp++); - for (int i = 128; i < 256; i++) - { - unsigned char b1 = arr[i*6 + 1], b2 = arr[i*6 + 2], b3 = arr[i*6 + 3]; - if (b1 == ch && b2 == ch2 && (len != 3 || b3 == ch3)) - { - *(out++) = (char)i; - return; - } - } + for (int i = 128; i < 256; i++) + { + unsigned char b1 = arr[i*6 + 1], b2 = arr[i*6 + 2], b3 = arr[i*6 + 3]; + if (b1 == ch && b2 == ch2 && (len != 3 || b3 == ch3)) + { + *(out++) = (char)i; + return; + } + } - std::cout << "Could not find glyph " << std::hex << (int)ch << " " << (int)ch2 << " " << (int)ch3 << std::endl; + std::cout << "Could not find glyph " << std::hex << (int)ch << " " << (int)ch2 << " " << (int)ch3 << std::endl; - *(out++) = ch; // Could not find glyph, just put whatever + *(out++) = ch; // Could not find glyph, just put whatever } std::string ToUTF8::getLegacyEnc(ToUTF8::FromType to) { - // Pick translation array - const char *arr; - switch (to) - { - case ToUTF8::WINDOWS_1252: + // Pick translation array + const char *arr; + switch (to) { - arr = ToUTF8::windows_1252; - break; + case ToUTF8::WINDOWS_1252: + { + arr = ToUTF8::windows_1252; + break; + } + case ToUTF8::WINDOWS_1250: + { + arr = ToUTF8::windows_1250; + break; + } + case ToUTF8::WINDOWS_1251: + { + arr = ToUTF8::windows_1251; + break; + } + default: + { + assert(0); + } } - case ToUTF8::WINDOWS_1250: - { - arr = ToUTF8::windows_1250; - break; - } - case ToUTF8::WINDOWS_1251: - { - arr = ToUTF8::windows_1251; - break; - } - default: - { - assert(0); - } - } - // Double check that the input string stops at some point (it might - // contain zero terminators before this, inside its own data, which - // is also ok.) - char* input = &buf[0]; - assert(input[size] == 0); + // Double check that the input string stops at some point (it might + // contain zero terminators before this, inside its own data, which + // is also ok.) + char* input = &buf[0]; + assert(input[size] == 0); - // TODO: The rest of this function is designed for single-character - // input encodings only. It also assumes that the input the input - // encoding shares its first 128 values (0-127) with ASCII. These - // conditions must be checked again if you add more input encodings - // later. + // TODO: The rest of this function is designed for single-character + // input encodings only. It also assumes that the input the input + // encoding shares its first 128 values (0-127) with ASCII. These + // conditions must be checked again if you add more input encodings + // later. - // Compute output length, and check for pure ascii input at the same - // time. - bool ascii; - size_t outlen = getLength2(arr, input, ascii); + // Compute output length, and check for pure ascii input at the same + // time. + bool ascii; + size_t outlen = getLength2(arr, input, ascii); - // If we're pure ascii, then don't bother converting anything. - if(ascii) - return std::string(input, outlen); + // If we're pure ascii, then don't bother converting anything. + if(ascii) + return std::string(input, outlen); - // Make sure the output is large enough - resize(output, outlen); - char *out = &output[0]; + // Make sure the output is large enough + resize(output, outlen); + char *out = &output[0]; - // Translate - while(*input) - copyFromArray2(arr, input, out); + // Translate + while(*input) + copyFromArray2(arr, input, out); - // Make sure that we wrote the correct number of bytes - assert((out-&output[0]) == (int)outlen); + // Make sure that we wrote the correct number of bytes + assert((out-&output[0]) == (int)outlen); - // And make extra sure the output is null terminated - assert(output.size() > outlen); - assert(output[outlen] == 0); + // And make extra sure the output is null terminated + assert(output.size() > outlen); + assert(output[outlen] == 0); - // Return a string - return std::string(&output[0], outlen); + // Return a string + return std::string(&output[0], outlen); } ToUTF8::FromType ToUTF8::calculateEncoding(const std::string& encodingName) { - if (encodingName == "win1250") - return ToUTF8::WINDOWS_1250; - else if (encodingName == "win1251") - return ToUTF8::WINDOWS_1251; - else - return ToUTF8::WINDOWS_1252; + if (encodingName == "win1250") + return ToUTF8::WINDOWS_1250; + else if (encodingName == "win1251") + return ToUTF8::WINDOWS_1251; + else + return ToUTF8::WINDOWS_1252; } std::string ToUTF8::encodingUsingMessage(const std::string& encodingName) { - if (encodingName == "win1250") - return "Using Central and Eastern European font encoding."; - else if (encodingName == "win1251") - return "Using Cyrillic font encoding."; - else - return "Using default (English) font encoding."; + if (encodingName == "win1250") + return "Using Central and Eastern European font encoding."; + else if (encodingName == "win1251") + return "Using Cyrillic font encoding."; + else + return "Using default (English) font encoding."; } diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index f52ae73bd..6877e2dc1 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -2,29 +2,66 @@ #define COMPONENTS_TOUTF8_H #include +#include +#include namespace ToUTF8 { - // These are all the currently supported code pages - enum FromType + // These are all the currently supported code pages + enum FromType { - WINDOWS_1250, // Central ane Eastern European languages - WINDOWS_1251, // Cyrillic languages - WINDOWS_1252 // Used by English version of Morrowind (and - // probably others) + WINDOWS_1250, // Central ane Eastern European languages + WINDOWS_1251, // Cyrillic languages + WINDOWS_1252 // Used by English version of Morrowind (and + // probably others) }; - // Return a writable buffer of at least 'size' bytes. The buffer - // does not have to be freed. - char* getBuffer(int size); + // Return a writable buffer of at least 'size' bytes. The buffer + // does not have to be freed. + char* getBuffer(int size); - // Convert the previously written buffer to UTF8 from the given code - // page. - std::string getUtf8(FromType from); - std::string getLegacyEnc(FromType to); + // Convert the previously written buffer to UTF8 from the given code + // page. + std::string getUtf8(FromType from); + std::string getLegacyEnc(FromType to); - FromType calculateEncoding(const std::string& encodingName); - std::string encodingUsingMessage(const std::string& encodingName); + FromType calculateEncoding(const std::string& encodingName); + std::string encodingUsingMessage(const std::string& encodingName); + + // class + + class Utf8Encoder + { + public: + Utf8Encoder(void); + + void setEncoding(const FromType sourceEncoding); + + // Convert to UTF8 from the previously given code page. + std::string getUtf8(const char *input, int size); + inline std::string getUtf8(const std::string &str) + { + return getUtf8(str.c_str(), str.size()); + } + + std::string getLegacyEnc(const char *input, int size); + inline std::string getLegacyEnc(const std::string &str) + { + return getLegacyEnc(str.c_str(), str.size()); + } + + private: + void resize(size_t size); + size_t getLength(const char* input, bool &ascii); + void copyFromArray(unsigned char chp, char* &out); + size_t getLength2(const char* input, bool &ascii); + void copyFromArray2(const char*& chp, char* &out); + + FromType mEncoding; + std::vector mOutput; + int mSize; + char* translationArray; + }; } #endif From 67273fc1777b45d9860fe114689cbdc9836c1f48 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 2 Jan 2013 23:39:21 +0100 Subject: [PATCH 234/916] mwiniimporter: use Utf8Encoder --- apps/mwiniimporter/importer.cpp | 12 +++--------- apps/mwiniimporter/importer.hpp | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index def70615b..5c3dedd04 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -649,11 +649,13 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) { std::string section(""); MwIniImporter::multistrmap map; boost::iostreams::streamfile(filename.c_str()); + ToUTF8::Utf8Encoder encoder; + encoder.setEncoding(mEncoding); std::string line; while (std::getline(file, line)) { - line = toUTF8(line); + line = encoder.getUtf8(line); // unify Unix-style and Windows file ending if (!(line.empty()) && (line[line.length()-1]) == '\r') { @@ -829,14 +831,6 @@ void MwIniImporter::writeToFile(boost::iostreams::stream #include -#include "../../components/to_utf8/to_utf8.hpp" +#include class MwIniImporter { public: From 9906c3051dddaaf435d55841f5e9d0d392d575c5 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 3 Jan 2013 15:01:08 +0100 Subject: [PATCH 235/916] components/translation: use Utf8Encoder --- components/translation/translation.cpp | 6 ++---- components/translation/translation.hpp | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index fb5b03861..002446e4f 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -50,10 +50,7 @@ namespace Translation if (!line.empty()) { - char* buffer = ToUTF8::getBuffer(line.size() + 1); - //buffer has at least line.size() + 1 bytes, so it must be safe - strcpy(buffer, line.c_str()); - line = ToUTF8::getUtf8(mEncoding); + line = mEncoder.getUtf8(line); size_t tab_pos = line.find('\t'); if (tab_pos != std::string::npos && tab_pos > 0 && tab_pos < line.size() - 1) @@ -107,6 +104,7 @@ namespace Translation void Storage::setEncoding (const ToUTF8::FromType& encoding) { mEncoding = encoding; + mEncoder.setEncoding(encoding); } bool Storage::hasTranslation() const diff --git a/components/translation/translation.hpp b/components/translation/translation.hpp index 80d44d871..6c3e4df86 100644 --- a/components/translation/translation.hpp +++ b/components/translation/translation.hpp @@ -35,6 +35,7 @@ namespace Translation ToUTF8::FromType mEncoding; + ToUTF8::Utf8Encoder mEncoder; ContainerType mCellNamesTranslations, mTopicIDs, mPhraseForms; }; } From 02bf02f288c407ad639ad15c8bc3a72ae56597b4 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 3 Jan 2013 21:15:18 +0100 Subject: [PATCH 236/916] ESMReader, ESMWriter: use Utf8Encoder --- components/esm/esmreader.cpp | 22 +++++++++++++++++++--- components/esm/esmreader.hpp | 6 ++++++ components/esm/esmwriter.cpp | 8 +++----- components/esm/esmwriter.hpp | 1 + 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 580e006df..5cd99a64a 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -13,6 +13,11 @@ ESM_Context ESMReader::getContext() return mCtx; } +ESMReader::ESMReader(void): + mBuffer(50*1024) +{ +} + void ESMReader::restoreContext(const ESM_Context &rc) { // Reopen the file if necessary @@ -325,11 +330,21 @@ void ESMReader::getExact(void*x, int size) std::string ESMReader::getString(int size) { - char *ptr = ToUTF8::getBuffer(size); - mEsm->read(ptr, size); + size_t s = size; + if (mBuffer.size() <= s) + // Add some extra padding to reduce the chance of having to resize + // again later. + mBuffer.resize(3*s); + + // And make sure the string is zero terminated + mBuffer[s] = 0; + + // read ESM data + char *ptr = &mBuffer[0]; + getExact(ptr, size); // Convert to UTF8 and return - return ToUTF8::getUtf8(mEncoding); + return mEncoder.getUtf8(ptr, size); } void ESMReader::fail(const std::string &msg) @@ -350,6 +365,7 @@ void ESMReader::fail(const std::string &msg) void ESMReader::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; + mEncoder.setEncoding(encoding); } } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 1d0f6f580..57503aea7 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -20,6 +20,8 @@ class ESMReader { public: + ESMReader(void); + /************************************************************************* * * Public type definitions @@ -244,9 +246,13 @@ private: // Special file signifier (see SpecialFile enum above) int mSpf; + // Buffer for ESM strings + std::vector mBuffer; + SaveData mSaveData; MasterList mMasters; ToUTF8::FromType mEncoding; + ToUTF8::Utf8Encoder mEncoder; }; } #endif diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index c1ae06490..a00c7971d 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -157,12 +157,8 @@ void ESMWriter::writeHString(const std::string& data) write("\0", 1); else { - char *ptr = ToUTF8::getBuffer(data.size()+1); - strncpy(ptr, &data[0], data.size()); - ptr[data.size()] = '\0'; - // Convert to UTF8 and return - std::string ascii = ToUTF8::getLegacyEnc(m_encoding); + std::string ascii = m_encoder.getLegacyEnc(data); write(ascii.c_str(), ascii.size()); } @@ -207,6 +203,8 @@ void ESMWriter::setEncoding(const std::string& encoding) // Default Latin encoding m_encoding = ToUTF8::WINDOWS_1252; } + + m_encoder.setEncoding(m_encoding); } } diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index d3777be81..20bc5da12 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -95,6 +95,7 @@ private: std::ostream* m_stream; std::streampos m_headerPos; ToUTF8::FromType m_encoding; + ToUTF8::Utf8Encoder m_encoder; int m_recordCount; HEDRstruct m_header; From 0bdf52a0719a756f3be97a988ff33784d02f7fcc Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 3 Jan 2013 23:21:14 +0100 Subject: [PATCH 237/916] components/to_utf8: keep only Utf8Encoder --- components/to_utf8/to_utf8.cpp | 314 --------------------------------- components/to_utf8/to_utf8.hpp | 9 - 2 files changed, 323 deletions(-) diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 8ac582b81..5efec36a4 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -41,13 +41,6 @@ // Generated tables #include "tables_gen.hpp" -// Shared global buffers, we love you. These initial sizes are large -// enough to hold the largest books in Morrowind.esm, but we will -// resize automaticall if necessary. -static std::vector buf (50*1024); -static std::vector output (50*1024); -static int size; - using namespace ToUTF8; Utf8Encoder::Utf8Encoder(void): @@ -330,313 +323,6 @@ void Utf8Encoder::copyFromArray2(const char*& chp, char* &out) *(out++) = ch; // Could not find glyph, just put whatever } -static void resize(std::vector &buf, size_t size) -{ - if(buf.size() <= size) - // Add some extra padding to reduce the chance of having to resize - // again later. - buf.resize(3*size); - - // And make sure the string is zero terminated - buf[size] = 0; -} - -// This is just used to spew out a reusable input buffer for the -// conversion process. -char *ToUTF8::getBuffer(int s) -{ - // Remember the requested size - size = s; - resize(buf, size); - return &buf[0]; -} - -/** Get the total length length needed to decode the given string with - the given translation array. The arrays are encoded with 6 bytes - per character, with the first giving the length and the next 5 the - actual data. - - The function serves a dual purpose for optimization reasons: it - checks if the input is pure ascii (all values are <= 127). If this - is the case, then the ascii parameter is set to true, and the - caller can optimize for this case. - */ -static size_t getLength(const char *arr, const char* input, bool &ascii) -{ - ascii = true; - size_t len = 0; - const char* ptr = input; - unsigned char inp = *ptr; - - // Do away with the ascii part of the string first (this is almost - // always the entire string.) - while(inp && inp < 128) - inp = *(++ptr); - len += (ptr-input); - - // If we're not at the null terminator at this point, then there - // were some non-ascii characters to deal with. Go to slow-mode for - // the rest of the string. - if(inp) - { - ascii = false; - while(inp) - { - // Find the translated length of this character in the - // lookup table. - len += arr[inp*6]; - inp = *(++ptr); - } - } - return len; -} - -// Translate one character 'ch' using the translation array 'arr', and -// advance the output pointer accordingly. -static void copyFromArray(const char *arr, unsigned char ch, char* &out) -{ - // Optimize for ASCII values - if(ch < 128) - { - *(out++) = ch; - return; - } - - const char *in = arr + ch*6; - int len = *(in++); - for(int i=0; i outlen); - assert(output[outlen] == 0); - - // Return a string - return std::string(&output[0], outlen); -} - -static size_t getLength2(const char *arr, const char* input, bool &ascii) -{ - ascii = true; - size_t len = 0; - const char* ptr = input; - unsigned char inp = *ptr; - - // Do away with the ascii part of the string first (this is almost - // always the entire string.) - while(inp && inp < 128) - inp = *(++ptr); - len += (ptr-input); - - // If we're not at the null terminator at this point, then there - // were some non-ascii characters to deal with. Go to slow-mode for - // the rest of the string. - if(inp) - { - ascii = false; - while(inp) - { - len += 1; - // Find the translated length of this character in the - // lookup table. - switch(inp) - { - case 0xe2: len -= 2; break; - case 0xc2: - case 0xcb: - case 0xc4: - case 0xc6: - case 0xc3: - case 0xd0: - case 0xd1: - case 0xd2: - case 0xc5: len -= 1; break; - } - - inp = *(++ptr); - } - } - return len; -} - -static void copyFromArray2(const char *arr, char*& chp, char* &out) -{ - unsigned char ch = *(chp++); - // Optimize for ASCII values - if(ch < 128) - { - *(out++) = ch; - return; - } - - int len = 1; - switch (ch) - { - case 0xe2: len = 3; break; - case 0xc2: - case 0xcb: - case 0xc4: - case 0xc6: - case 0xc3: - case 0xd0: - case 0xd1: - case 0xd2: - case 0xc5: len = 2; break; - } - - if (len == 1) // There is no 1 length utf-8 glyph that is not 0x20 (empty space) - { - *(out++) = ch; - return; - } - - unsigned char ch2 = *(chp++); - unsigned char ch3 = '\0'; - if (len == 3) - ch3 = *(chp++); - - for (int i = 128; i < 256; i++) - { - unsigned char b1 = arr[i*6 + 1], b2 = arr[i*6 + 2], b3 = arr[i*6 + 3]; - if (b1 == ch && b2 == ch2 && (len != 3 || b3 == ch3)) - { - *(out++) = (char)i; - return; - } - } - - std::cout << "Could not find glyph " << std::hex << (int)ch << " " << (int)ch2 << " " << (int)ch3 << std::endl; - - *(out++) = ch; // Could not find glyph, just put whatever -} - -std::string ToUTF8::getLegacyEnc(ToUTF8::FromType to) -{ - // Pick translation array - const char *arr; - switch (to) - { - case ToUTF8::WINDOWS_1252: - { - arr = ToUTF8::windows_1252; - break; - } - case ToUTF8::WINDOWS_1250: - { - arr = ToUTF8::windows_1250; - break; - } - case ToUTF8::WINDOWS_1251: - { - arr = ToUTF8::windows_1251; - break; - } - default: - { - assert(0); - } - } - - // Double check that the input string stops at some point (it might - // contain zero terminators before this, inside its own data, which - // is also ok.) - char* input = &buf[0]; - assert(input[size] == 0); - - // TODO: The rest of this function is designed for single-character - // input encodings only. It also assumes that the input the input - // encoding shares its first 128 values (0-127) with ASCII. These - // conditions must be checked again if you add more input encodings - // later. - - // Compute output length, and check for pure ascii input at the same - // time. - bool ascii; - size_t outlen = getLength2(arr, input, ascii); - - // If we're pure ascii, then don't bother converting anything. - if(ascii) - return std::string(input, outlen); - - // Make sure the output is large enough - resize(output, outlen); - char *out = &output[0]; - - // Translate - while(*input) - copyFromArray2(arr, input, out); - - // Make sure that we wrote the correct number of bytes - assert((out-&output[0]) == (int)outlen); - - // And make extra sure the output is null terminated - assert(output.size() > outlen); - assert(output[outlen] == 0); - - // Return a string - return std::string(&output[0], outlen); -} - ToUTF8::FromType ToUTF8::calculateEncoding(const std::string& encodingName) { if (encodingName == "win1250") diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index 6877e2dc1..bfba8a1ac 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -16,15 +16,6 @@ namespace ToUTF8 // probably others) }; - // Return a writable buffer of at least 'size' bytes. The buffer - // does not have to be freed. - char* getBuffer(int size); - - // Convert the previously written buffer to UTF8 from the given code - // page. - std::string getUtf8(FromType from); - std::string getLegacyEnc(FromType to); - FromType calculateEncoding(const std::string& encodingName); std::string encodingUsingMessage(const std::string& encodingName); From 019893b5c677c1fd605e106cb22295805f2e019a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 3 Jan 2013 23:44:58 -0800 Subject: [PATCH 238/916] Get rid of some unnecessary case-insensitive compares --- components/nifogre/ogre_nif_loader.cpp | 21 ++++++++------------- components/nifogre/ogre_nif_loader.hpp | 17 ----------------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index ad51d50b9..b3ceb089e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -43,6 +43,7 @@ #include +#include #include #include @@ -219,7 +220,7 @@ struct KeyTimeSort }; -typedef std::map LoaderMap; +typedef std::map LoaderMap; static LoaderMap sLoaders; public: @@ -918,7 +919,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } - typedef std::map LoaderMap; + typedef std::map LoaderMap; static LoaderMap sLoaders; public: @@ -1101,13 +1102,6 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke return entitylist; } -struct checklow { - bool operator()(const char &a, const char &b) const - { - return ::tolower(a) == ::tolower(b); - } -}; - EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, const std::string &name, @@ -1120,18 +1114,19 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = "Tri "+bonename; + std::string filter = "tri "+bonename; + std::transform(filter.begin()+4, filter.end(), filter.begin()+4, ::tolower); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first->getName()); if(ent->hasSkeleton()) { + std::transform(meshes[i].second.begin(), meshes[i].second.end(), meshes[i].second.begin(), ::tolower); + if(meshes[i].second.length() < filter.length() || - std::mismatch(filter.begin(), filter.end(), meshes[i].second.begin(), checklow()).first != filter.end()) + meshes[i].second.compare(0, filter.length(), filter) != 0) { sceneMgr->destroyEntity(ent); - meshes.erase(meshes.begin()+i); - i--; continue; } if(!entitylist.mSkelBase) diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index a203112b5..08a233245 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -30,23 +30,6 @@ #include #include -#include -#include - -#include "../nif/node.hpp" - -#include - -class BoundsFinder; - -struct ciLessBoost : std::binary_function -{ - bool operator() (const std::string & s1, const std::string & s2) const - { - //case insensitive version of is_less - return boost::algorithm::lexicographical_compare(s1, s2, boost::algorithm::is_iless()); - } -}; namespace Nif { From 61ad8bb3ddcc1ec2a599a34a9a63d6707faaaae8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 00:14:41 -0800 Subject: [PATCH 239/916] Use a list of mesh names instead of mesh objects --- components/nifogre/ogre_nif_loader.cpp | 6 +++--- components/nifogre/ogre_nif_loader.hpp | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b3ceb089e..9e17736ef 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1005,7 +1005,7 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(std::make_pair(mesh, shape->name)); + meshes.push_back(std::make_pair(mesh->getName(), shape->name)); } else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && node->recType != Nif::RC_NiRotatingParticles) @@ -1072,7 +1072,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke Ogre::SceneManager *sceneMgr = parent->getCreator(); for(size_t i = 0;i < meshes.size();i++) { - entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first->getName())); + entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first)); Ogre::Entity *entity = entitylist.mEntities.back(); if(!entitylist.mSkelBase && entity->hasSkeleton()) entitylist.mSkelBase = entity; @@ -1118,7 +1118,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo std::transform(filter.begin()+4, filter.end(), filter.begin()+4, ::tolower); for(size_t i = 0;i < meshes.size();i++) { - Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first->getName()); + Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first); if(ent->hasSkeleton()) { std::transform(meshes[i].second.begin(), meshes[i].second.end(), meshes[i].second.begin(), ::tolower); diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 08a233245..74b6f44df 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -52,9 +52,8 @@ struct EntityList { }; -/** This holds a list of meshes along with the names of their parent nodes - */ -typedef std::vector< std::pair > MeshPairList; +/** This holds a list of mesh names along with the names of their parent nodes */ +typedef std::vector< std::pair > MeshPairList; /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into From c947d87ab9e9510e322d8cb030f42b64f6f07dc4 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Fri, 4 Jan 2013 15:10:30 +0100 Subject: [PATCH 240/916] Add a test for to_utf8 component --- components/to_utf8/tests/.gitignore | 1 + .../to_utf8/tests/output/to_utf8_test.out | 4 ++ components/to_utf8/tests/test.sh | 18 ++++++ components/to_utf8/tests/to_utf8_test.cpp | 61 +++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 components/to_utf8/tests/.gitignore create mode 100644 components/to_utf8/tests/output/to_utf8_test.out create mode 100755 components/to_utf8/tests/test.sh create mode 100644 components/to_utf8/tests/to_utf8_test.cpp diff --git a/components/to_utf8/tests/.gitignore b/components/to_utf8/tests/.gitignore new file mode 100644 index 000000000..814490404 --- /dev/null +++ b/components/to_utf8/tests/.gitignore @@ -0,0 +1 @@ +*_test diff --git a/components/to_utf8/tests/output/to_utf8_test.out b/components/to_utf8/tests/output/to_utf8_test.out new file mode 100644 index 000000000..dcb32359a --- /dev/null +++ b/components/to_utf8/tests/output/to_utf8_test.out @@ -0,0 +1,4 @@ +original: Без вопроÑов отдаете ему рулет, знаÑ, что позже вы Ñможете привеÑти Ñ Ñобой Ñвоих друзей и тогда он получит по заÑлугам? +converted: Без вопроÑов отдаете ему рулет, знаÑ, что позже вы Ñможете привеÑти Ñ Ñобой Ñвоих друзей и тогда он получит по заÑлугам? +original: Vous lui donnez le gâteau sans protester avant d’aller chercher tous vos amis et de revenir vous venger. +converted: Vous lui donnez le gâteau sans protester avant d’aller chercher tous vos amis et de revenir vous venger. diff --git a/components/to_utf8/tests/test.sh b/components/to_utf8/tests/test.sh new file mode 100755 index 000000000..2d07708ad --- /dev/null +++ b/components/to_utf8/tests/test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +make || exit + +mkdir -p output + +PROGS=*_test + +for a in $PROGS; do + if [ -f "output/$a.out" ]; then + echo "Running $a:" + ./$a | diff output/$a.out - + else + echo "Creating $a.out" + ./$a > "output/$a.out" + git add "output/$a.out" + fi +done diff --git a/components/to_utf8/tests/to_utf8_test.cpp b/components/to_utf8/tests/to_utf8_test.cpp new file mode 100644 index 000000000..8c25c483e --- /dev/null +++ b/components/to_utf8/tests/to_utf8_test.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +#include "../to_utf8.hpp" + +std::string getFirstLine(const std::string &filename); +void testEncoder(ToUTF8::FromType encoding, const std::string &legacyEncFile, + const std::string &utf8File); + +/// Test character encoding conversion to and from UTF-8 +void testEncoder(ToUTF8::FromType encoding, const std::string &legacyEncFile, + const std::string &utf8File) +{ + // get some test data + std::string legacyEncLine = getFirstLine(legacyEncFile); + std::string utf8Line = getFirstLine(utf8File); + + // create an encoder for specified character encoding + ToUTF8::Utf8Encoder encoder; + encoder.setEncoding(encoding); + + // convert text to UTF-8 + std::string convertedUtf8Line = encoder.getUtf8(legacyEncLine); + + std::cout << "original: " << utf8Line << std::endl; + std::cout << "converted: " << convertedUtf8Line << std::endl; + + // check correctness + assert(convertedUtf8Line == utf8Line); + + // convert UTF-8 text to legacy encoding + std::string convertedLegacyEncLine = encoder.getLegacyEnc(utf8Line); + // check correctness + assert(convertedLegacyEncLine == legacyEncLine); +} + +std::string getFirstLine(const std::string &filename) +{ + std::string line; + std::ifstream text (filename.c_str()); + + if (!text.is_open()) + { + throw std::runtime_error("Unable to open file " + filename); + } + + std::getline(text, line); + text.close(); + + return line; +} + +int main() +{ + testEncoder(ToUTF8::WINDOWS_1251, "data/russian-win1251.txt", "data/russian-utf8.txt"); + testEncoder(ToUTF8::WINDOWS_1252, "data/french-win1252.txt", "data/french-utf8.txt"); + return 0; +} From cc792da85895c85db8b76a5c9692bc260f35f649 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Fri, 4 Jan 2013 15:24:07 +0100 Subject: [PATCH 241/916] Fix to_utf8 test: add test data directory and remove unused include --- components/to_utf8/tests/test_data/french-utf8.txt | 1 + components/to_utf8/tests/test_data/french-win1252.txt | 1 + components/to_utf8/tests/test_data/russian-utf8.txt | 1 + components/to_utf8/tests/test_data/russian-win1251.txt | 1 + components/to_utf8/tests/to_utf8_test.cpp | 5 ++--- 5 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 components/to_utf8/tests/test_data/french-utf8.txt create mode 100644 components/to_utf8/tests/test_data/french-win1252.txt create mode 100644 components/to_utf8/tests/test_data/russian-utf8.txt create mode 100644 components/to_utf8/tests/test_data/russian-win1251.txt diff --git a/components/to_utf8/tests/test_data/french-utf8.txt b/components/to_utf8/tests/test_data/french-utf8.txt new file mode 100644 index 000000000..aaaccac73 --- /dev/null +++ b/components/to_utf8/tests/test_data/french-utf8.txt @@ -0,0 +1 @@ +Vous lui donnez le gâteau sans protester avant d’aller chercher tous vos amis et de revenir vous venger. \ No newline at end of file diff --git a/components/to_utf8/tests/test_data/french-win1252.txt b/components/to_utf8/tests/test_data/french-win1252.txt new file mode 100644 index 000000000..1de4593e9 --- /dev/null +++ b/components/to_utf8/tests/test_data/french-win1252.txt @@ -0,0 +1 @@ +Vous lui donnez le gâteau sans protester avant d’aller chercher tous vos amis et de revenir vous venger. \ No newline at end of file diff --git a/components/to_utf8/tests/test_data/russian-utf8.txt b/components/to_utf8/tests/test_data/russian-utf8.txt new file mode 100644 index 000000000..eb20b32dd --- /dev/null +++ b/components/to_utf8/tests/test_data/russian-utf8.txt @@ -0,0 +1 @@ +Без вопроÑов отдаете ему рулет, знаÑ, что позже вы Ñможете привеÑти Ñ Ñобой Ñвоих друзей и тогда он получит по заÑлугам? \ No newline at end of file diff --git a/components/to_utf8/tests/test_data/russian-win1251.txt b/components/to_utf8/tests/test_data/russian-win1251.txt new file mode 100644 index 000000000..086e57edd --- /dev/null +++ b/components/to_utf8/tests/test_data/russian-win1251.txt @@ -0,0 +1 @@ +Áåç âîïðîñîâ îòäàåòå åìó ðóëåò, çíàÿ, ÷òî ïîçæå âû ñìîæåòå ïðèâåñòè ñ ñîáîé ñâîèõ äðóçåé è òîãäà îí ïîëó÷èò ïî çàñëóãàì? \ No newline at end of file diff --git a/components/to_utf8/tests/to_utf8_test.cpp b/components/to_utf8/tests/to_utf8_test.cpp index 8c25c483e..4bba0cf90 100644 --- a/components/to_utf8/tests/to_utf8_test.cpp +++ b/components/to_utf8/tests/to_utf8_test.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include "../to_utf8.hpp" @@ -55,7 +54,7 @@ std::string getFirstLine(const std::string &filename) int main() { - testEncoder(ToUTF8::WINDOWS_1251, "data/russian-win1251.txt", "data/russian-utf8.txt"); - testEncoder(ToUTF8::WINDOWS_1252, "data/french-win1252.txt", "data/french-utf8.txt"); + testEncoder(ToUTF8::WINDOWS_1251, "test_data/russian-win1251.txt", "test_data/russian-utf8.txt"); + testEncoder(ToUTF8::WINDOWS_1252, "test_data/french-win1252.txt", "test_data/french-utf8.txt"); return 0; } From 3c91f7793b29d2c9479b3ca15e4b327cd87e08f2 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 4 Jan 2013 08:40:33 -0800 Subject: [PATCH 242/916] overrode MyGUI::DataManager::isDataExist Created a override of MyGUI::DataManager::isDataExist to fix a performance issue with MyGUI startup. This required moving the functionality of MyGUI::OgrePlatform into OEngine::GUI::MyGUIManager so that a new version of the MyGUI::DataManager could be created. --- libs/openengine/gui/manager.cpp | 47 +++++++++++++++++++++++++++------ libs/openengine/gui/manager.hpp | 11 +++++--- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index acb4ed9df..925891e1b 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -6,6 +6,19 @@ using namespace OEngine::GUI; +/* + * As of MyGUI 3.2.0, MyGUI::OgreDataManager::isDataExist is unnecessarily complex + * this override fixes the resulting performance issue. + */ +class FixedOgreDataManager : public MyGUI::OgreDataManager +{ +public: + bool isDataExist(const std::string& _name) + { + return Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup (_name); + } +}; + void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir) { assert(wnd); @@ -25,11 +38,18 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool if(!logDir.empty()) theLogFile.insert(0, logDir); - // Set up OGRE platform. We might make this more generic later. - mPlatform = new OgrePlatform(); - LogManager::getInstance().setSTDOutputEnabled(logging); - mPlatform->initialise(wnd, mgr, "General", theLogFile); + // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. + mLogManager = new LogManager(); + mRenderManager = new OgreRenderManager(); + mDataManager = new FixedOgreDataManager(); + LogManager::getInstance().setSTDOutputEnabled(logging); + + if (!theLogFile.empty()) + LogManager::getInstance().createDefaultSource(theLogFile); + + mRenderManager->initialise(wnd, mgr); + mDataManager->initialise("General"); // Create GUI mGui = new Gui(); @@ -40,11 +60,22 @@ void MyGUIManager::shutdown() { mGui->shutdown (); delete mGui; - if(mPlatform) + if(mRenderManager) { - mPlatform->shutdown(); - delete mPlatform; + mRenderManager->shutdown(); + delete mRenderManager; + mRenderManager = NULL; + } + if(mDataManager) + { + mDataManager->shutdown(); + delete mDataManager; + mDataManager = NULL; + } + if (mLogManager) + { + delete mLogManager; + mLogManager = NULL; } mGui = NULL; - mPlatform = NULL; } diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index 1ec2e2fcf..c0f98da88 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -3,8 +3,10 @@ namespace MyGUI { - class OgrePlatform; class Gui; + class LogManager; + class OgreDataManager; + class OgreRenderManager; } namespace Ogre @@ -18,12 +20,15 @@ namespace GUI { class MyGUIManager { - MyGUI::OgrePlatform *mPlatform; MyGUI::Gui *mGui; + MyGUI::LogManager* mLogManager; + MyGUI::OgreDataManager* mDataManager; + MyGUI::OgreRenderManager* mRenderManager; Ogre::SceneManager* mSceneMgr; + public: - MyGUIManager() : mPlatform(NULL), mGui(NULL) {} + MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL), mGui(NULL) {} MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) { setup(wnd,mgr,logging, logDir); From 218139351830d00b3b564b13ab7d16276b99c6d3 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 4 Jan 2013 11:36:22 -0800 Subject: [PATCH 243/916] change texture renaming logic to increase performance ResourceGroupManager::resourceExistsInAnyGroup is slow (at least on windows) if the tested path does not exist, but is fast if it does (due to finding it in the index). This change tries the '.dds' version of the name first, and reverts to the original if the '.dds' version was not found. --- components/nifogre/ogre_nif_loader.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index ad51d50b9..dca459119 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -536,11 +536,23 @@ static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &nam * textures from tga to dds for increased load speed, but all * texture file name references were kept as .tga. */ - texName = "textures\\" + st->filename; - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + + static const char * path = "textures\\"; + + texName = path + st->filename; + + Ogre::String::size_type pos = texName.rfind('.'); + + if (texName.compare (pos, texName.size () - pos, ".dds") != 0) { - Ogre::String::size_type pos = texName.rfind('.'); + // since we know all (GOTY edition or less) textures end + // in .dds, we change the extension texName.replace(pos, texName.length(), ".dds"); + + // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) + // verify, and revert if false (this call succeeds quickly, but fails slowly) + if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + texName = path + st->filename; } } else warn("Found internal texture, ignoring."); From dcfa902525ef76cfab2426c03965a6a0291b7c53 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 4 Jan 2013 13:08:09 -0800 Subject: [PATCH 244/916] fixed error in cmake when disabling esmtool --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 36e45d78a..766167672 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -534,7 +534,9 @@ if (WIN32) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif (BUILD_LAUNCHER) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) - set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) + if (BUILD_ESMTOOL) + set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) + endif (BUILD_ESMTOOL) endif(MSVC) # Same for MinGW From 5c7f1bd497d620e1d219b485eebb6fb9f8c598ab Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 1 Jan 2013 12:55:39 -0800 Subject: [PATCH 245/916] moved ConstrainedDataStream into its own file moved the ConstrainedDataStream into its own source file and changed BSAFile to use it though the exposed factory function. This is in preperation foreimplementing it based on feedback from profiling that (at least on windows) the C++ iostreams library is quite slow. --- components/CMakeLists.txt | 2 +- components/bsa/bsa_file.cpp | 89 +------------- .../files/constrainedfiledatastream.cpp | 112 ++++++++++++++++++ .../files/constrainedfiledatastream.hpp | 8 ++ 4 files changed, 126 insertions(+), 85 deletions(-) create mode 100644 components/files/constrainedfiledatastream.cpp create mode 100644 components/files/constrainedfiledatastream.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f3d5f4aee..f54efab22 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -48,7 +48,7 @@ add_component_dir (misc add_component_dir (files linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager - filelibrary ogreplugin + filelibrary ogreplugin constrainedfiledatastream ) add_component_dir (compiler diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 1700e1aab..5e529e18e 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -23,94 +23,15 @@ #include "bsa_file.hpp" -#include -#include -#include +//#include +//#include +//#include -#include +#include "../files/constrainedfiledatastream.hpp" using namespace std; using namespace Bsa; -class ConstrainedDataStream : public Ogre::DataStream { - std::ifstream mStream; - const size_t mStart; - size_t mPos; - bool mIsEOF; - -public: - ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length) - : mStream(fname.c_str(), std::ios_base::binary), mStart(start), mPos(0), mIsEOF(false) - { - mSize = length; - if(!mStream.seekg(mStart, std::ios_base::beg)) - throw std::runtime_error("Error seeking to start of BSA entry"); - } - - ConstrainedDataStream(const Ogre::String &name, const Ogre::String &fname, - size_t start, size_t length) - : Ogre::DataStream(name), mStream(fname.c_str(), std::ios_base::binary), - mStart(start), mPos(0), mIsEOF(false) - { - mSize = length; - if(!mStream.seekg(mStart, std::ios_base::beg)) - throw std::runtime_error("Error seeking to start of BSA entry"); - } - - - virtual size_t read(void *buf, size_t count) - { - mStream.clear(); - - if(count > mSize-mPos) - { - count = mSize-mPos; - mIsEOF = true; - } - mStream.read(reinterpret_cast(buf), count); - - count = mStream.gcount(); - mPos += count; - return count; - } - - virtual void skip(long count) - { - if((count >= 0 && (size_t)count <= mSize-mPos) || - (count < 0 && (size_t)-count <= mPos)) - { - mStream.clear(); - if(mStream.seekg(count, std::ios_base::cur)) - { - mPos += count; - mIsEOF = false; - } - } - } - - virtual void seek(size_t pos) - { - if(pos < mSize) - { - mStream.clear(); - if(mStream.seekg(pos+mStart, std::ios_base::beg)) - { - mPos = pos; - mIsEOF = false; - } - } - } - - virtual size_t tell() const - { return mPos; } - - virtual bool eof() const - { return mIsEOF; } - - virtual void close() - { mStream.close(); } -}; - /// Error handling void BSAFile::fail(const string &msg) @@ -253,5 +174,5 @@ Ogre::DataStreamPtr BSAFile::getFile(const char *file) fail("File not found: " + string(file)); const FileStruct &fs = files[i]; - return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, fs.offset, fs.fileSize)); + return openConstrainedFileDataStream (filename.c_str (), fs.offset, fs.fileSize); } diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp new file mode 100644 index 000000000..037ffe6f0 --- /dev/null +++ b/components/files/constrainedfiledatastream.cpp @@ -0,0 +1,112 @@ +/* + OpenMW - The completely unofficial reimplementation of Morrowind + Copyright (C) 2008-2010 Nicolay Korslund + Email: < korslund@gmail.com > + WWW: http://openmw.sourceforge.net/ + + This file (bsa_file.cpp) is part of the OpenMW package. + + OpenMW is distributed as free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + version 3, as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + version 3 along with this program. If not, see + http://www.gnu.org/licenses/ . + + */ + +#include "constrainedfiledatastream.hpp" + +#include + +class ConstrainedDataStream : public Ogre::DataStream { + std::ifstream mStream; + const size_t mStart; + size_t mPos; + bool mIsEOF; + +public: + ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length) + : mStream(fname.c_str(), std::ios_base::binary), mStart(start), mPos(0), mIsEOF(false) + { + mSize = length; + if(!mStream.seekg(mStart, std::ios_base::beg)) + throw std::runtime_error("Error seeking to start of BSA entry"); + } + + ConstrainedDataStream(const Ogre::String &name, const Ogre::String &fname, + size_t start, size_t length) + : Ogre::DataStream(name), mStream(fname.c_str(), std::ios_base::binary), + mStart(start), mPos(0), mIsEOF(false) + { + mSize = length; + if(!mStream.seekg(mStart, std::ios_base::beg)) + throw std::runtime_error("Error seeking to start of BSA entry"); + } + + + virtual size_t read(void *buf, size_t count) + { + mStream.clear(); + + if(count > mSize-mPos) + { + count = mSize-mPos; + mIsEOF = true; + } + mStream.read(reinterpret_cast(buf), count); + + count = mStream.gcount(); + mPos += count; + return count; + } + + virtual void skip(long count) + { + if((count >= 0 && (size_t)count <= mSize-mPos) || + (count < 0 && (size_t)-count <= mPos)) + { + mStream.clear(); + if(mStream.seekg(count, std::ios_base::cur)) + { + mPos += count; + mIsEOF = false; + } + } + } + + virtual void seek(size_t pos) + { + if(pos < mSize) + { + mStream.clear(); + if(mStream.seekg(pos+mStart, std::ios_base::beg)) + { + mPos = pos; + mIsEOF = false; + } + } + } + + virtual size_t tell() const + { return mPos; } + + virtual bool eof() const + { return mIsEOF; } + + virtual void close() + { mStream.close(); } +}; + +Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset, size_t length) +{ + assert (length != 0xFFFFFFFF); // reserved for future use... + + return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, offset, length)); +} diff --git a/components/files/constrainedfiledatastream.hpp b/components/files/constrainedfiledatastream.hpp new file mode 100644 index 000000000..367defcbc --- /dev/null +++ b/components/files/constrainedfiledatastream.hpp @@ -0,0 +1,8 @@ +#ifndef COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP +#define COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP + +#include + +Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset = 0, size_t length = 0xFFFFFFFF); + +#endif // COMPONENTS_FILES_CONSTRAINEDFILEDATASTREAM_HPP From 278337116b93e62e7458e03463e83c2055eb15e7 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 1 Jan 2013 15:07:33 -0800 Subject: [PATCH 246/916] increased performance of ConstrainedDataStream Reimplemented ConstrainedDataStream to use low-level IO calls and a custom buffering scheme to avoid using C++ iostreams. --- components/CMakeLists.txt | 2 +- .../files/constrainedfiledatastream.cpp | 228 ++++++++----- components/files/lowlevelfile.cpp | 299 ++++++++++++++++++ components/files/lowlevelfile.hpp | 54 ++++ 4 files changed, 497 insertions(+), 86 deletions(-) create mode 100644 components/files/lowlevelfile.cpp create mode 100644 components/files/lowlevelfile.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f54efab22..3da09ecb8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -48,7 +48,7 @@ add_component_dir (misc add_component_dir (files linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager - filelibrary ogreplugin constrainedfiledatastream + filelibrary ogreplugin constrainedfiledatastream lowlevelfile ) add_component_dir (compiler diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp index 037ffe6f0..2f75ce41b 100644 --- a/components/files/constrainedfiledatastream.cpp +++ b/components/files/constrainedfiledatastream.cpp @@ -1,112 +1,170 @@ -/* - OpenMW - The completely unofficial reimplementation of Morrowind - Copyright (C) 2008-2010 Nicolay Korslund - Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ - - This file (bsa_file.cpp) is part of the OpenMW package. - - OpenMW is distributed as free software: you can redistribute it - and/or modify it under the terms of the GNU General Public License - version 3, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . - - */ - #include "constrainedfiledatastream.hpp" +#include "lowlevelfile.hpp" #include +#include + +namespace { class ConstrainedDataStream : public Ogre::DataStream { - std::ifstream mStream; - const size_t mStart; - size_t mPos; - bool mIsEOF; - public: + + static const size_t sBufferSize = 4096; // somewhat arbitrary though 64KB buffers didn't seem to improve performance any + static const size_t sBufferThreshold = 1024; // reads larger than this bypass buffering as cost of memcpy outweighs cost of system call + ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length) - : mStream(fname.c_str(), std::ios_base::binary), mStart(start), mPos(0), mIsEOF(false) + { + mFile.open (fname.c_str ()); + mSize = length != 0xFFFFFFFF ? length : mFile.size () - start; + + mPos = 0; + mOrigin = start; + mExtent = start + mSize; + + mBufferOrigin = 0; + mBufferExtent = 0; + } + + + size_t read(void* buf, size_t count) + { + assert (mPos <= mSize); + + uint8_t * out = reinterpret_cast (buf); + + size_t posBeg = mOrigin + mPos; + size_t posEnd = posBeg + count; + + if (posEnd > mExtent) + posEnd = mExtent; + + size_t posCur = posBeg; + + while (posCur != posEnd) + { + size_t readLeft = posEnd - posCur; + + if (posCur < mBufferOrigin || posCur >= mBufferExtent) + { + if (readLeft >= sBufferThreshold || (posCur == mOrigin && posEnd == mExtent)) + { + assert (mFile.tell () == mBufferExtent); + + if (posCur != mBufferExtent) + mFile.seek (posCur); + + posCur += mFile.read (out, readLeft); + + mBufferOrigin = mBufferExtent = posCur; + + mPos = posCur - mOrigin; + + return posCur - posBeg; + } + else + { + size_t newBufferOrigin; + + if ((posCur < mBufferOrigin) && (mBufferOrigin - posCur < sBufferSize)) + newBufferOrigin = std::max (mOrigin, mBufferOrigin > sBufferSize ? mBufferOrigin - sBufferSize : 0); + else + newBufferOrigin = posCur; + + fill (newBufferOrigin); + } + } + + size_t xfer = std::min (readLeft, mBufferExtent - posCur); + + memcpy (out, mBuffer + (posCur - mBufferOrigin), xfer); + + posCur += xfer; + out += xfer; + } + + count = posEnd - posBeg; + mPos += count; + return count; + } + + void skip(long count) { - mSize = length; - if(!mStream.seekg(mStart, std::ios_base::beg)) - throw std::runtime_error("Error seeking to start of BSA entry"); - } + assert (mPos <= mSize); - ConstrainedDataStream(const Ogre::String &name, const Ogre::String &fname, - size_t start, size_t length) - : Ogre::DataStream(name), mStream(fname.c_str(), std::ios_base::binary), - mStart(start), mPos(0), mIsEOF(false) - { - mSize = length; - if(!mStream.seekg(mStart, std::ios_base::beg)) - throw std::runtime_error("Error seeking to start of BSA entry"); - } - - - virtual size_t read(void *buf, size_t count) - { - mStream.clear(); - - if(count > mSize-mPos) - { - count = mSize-mPos; - mIsEOF = true; - } - mStream.read(reinterpret_cast(buf), count); - - count = mStream.gcount(); - mPos += count; - return count; - } - - virtual void skip(long count) - { if((count >= 0 && (size_t)count <= mSize-mPos) || (count < 0 && (size_t)-count <= mPos)) - { - mStream.clear(); - if(mStream.seekg(count, std::ios_base::cur)) - { - mPos += count; - mIsEOF = false; - } - } + mPos += count; } - virtual void seek(size_t pos) + void seek(size_t pos) { - if(pos < mSize) - { - mStream.clear(); - if(mStream.seekg(pos+mStart, std::ios_base::beg)) - { - mPos = pos; - mIsEOF = false; - } - } + assert (mPos <= mSize); + + if (pos < mSize) + mPos = pos; } virtual size_t tell() const - { return mPos; } + { + assert (mPos <= mSize); + + return mPos; + } virtual bool eof() const - { return mIsEOF; } + { + assert (mPos <= mSize); + + return mPos == mSize; + } virtual void close() - { mStream.close(); } + { + mFile.close(); + } + +private: + + void fill (size_t newOrigin) + { + assert (mFile.tell () == mBufferExtent); + + size_t newExtent = newOrigin + sBufferSize; + + if (newExtent > mExtent) + newExtent = mExtent; + + size_t oldExtent = mBufferExtent; + + if (newOrigin != oldExtent) + mFile.seek (newOrigin); + + mBufferOrigin = mBufferExtent = newOrigin; + + size_t amountRequested = newExtent - newOrigin; + + size_t amountRead = mFile.read (mBuffer, amountRequested); + + if (amountRead != amountRequested) + throw std::runtime_error ("An unexpected condition occurred while reading from a file."); + + mBufferExtent = newExtent; + } + + LowLevelFile mFile; + + size_t mOrigin; + size_t mExtent; + size_t mPos; + + uint8_t mBuffer [sBufferSize]; + size_t mBufferOrigin; + size_t mBufferExtent; }; +} // end of unnamed namespace + Ogre::DataStreamPtr openConstrainedFileDataStream (char const * filename, size_t offset, size_t length) { - assert (length != 0xFFFFFFFF); // reserved for future use... - return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, offset, length)); } diff --git a/components/files/lowlevelfile.cpp b/components/files/lowlevelfile.cpp new file mode 100644 index 000000000..71fd1b523 --- /dev/null +++ b/components/files/lowlevelfile.cpp @@ -0,0 +1,299 @@ +#include "lowlevelfile.hpp" + +#include +#include +#include + +#if FILE_API == FILE_API_POSIX +#include +#include +#include +#endif + +#if FILE_API == FILE_API_STDIO +/* + * + * Implementation of LowLevelFile methods using c stdio + * + */ + +LowLevelFile::LowLevelFile () +{ + mHandle = NULL; +} + +LowLevelFile::~LowLevelFile () +{ + if (mHandle != NULL) + fclose (mHandle); +} + +void LowLevelFile::open (char const * filename) +{ + assert (mHandle == NULL); + + mHandle = fopen (filename, "rb"); + + if (mHandle == NULL) + { + std::ostringstream os; + os << "Failed to open '" << filename << "' for reading."; + throw std::runtime_error (os.str ()); + } +} + +void LowLevelFile::close () +{ + assert (mHandle != NULL); + + fclose (mHandle); + + mHandle = NULL; +} + +size_t LowLevelFile::size () +{ + assert (mHandle != NULL); + + long oldPosition = ftell (mHandle); + + if (oldPosition == -1) + throw std::runtime_error ("A query operation on a file failed."); + + if (fseek (mHandle, 0, SEEK_END) != 0) + throw std::runtime_error ("A query operation on a file failed."); + + long Size = ftell (mHandle); + + if (Size == -1) + throw std::runtime_error ("A query operation on a file failed."); + + if (fseek (mHandle, oldPosition, SEEK_SET) != 0) + throw std::runtime_error ("A query operation on a file failed."); + + return size_t (Size); +} + +void LowLevelFile::seek (size_t Position) +{ + assert (mHandle != NULL); + + if (fseek (mHandle, Position, SEEK_SET) != 0) + throw std::runtime_error ("A seek operation on a file failed."); +} + +size_t LowLevelFile::tell () +{ + assert (mHandle != NULL); + + long Position = ftell (mHandle); + + if (Position == -1) + throw std::runtime_error ("A query operation on a file failed."); + + return size_t (Position); +} + +size_t LowLevelFile::read (void * data, size_t size) +{ + assert (mHandle != NULL); + + int amount = fread (data, 1, size, mHandle); + + if (amount == 0 && ferror (mHandle)) + throw std::runtime_error ("A read operation on a file failed."); + + return amount; +} + +#elif FILE_API == FILE_API_POSIX +/* + * + * Implementation of LowLevelFile methods using posix IO calls + * + */ + +LowLevelFile::LowLevelFile () +{ + mHandle = -1; +} + +LowLevelFile::~LowLevelFile () +{ + if (mHandle != -1) + ::close (mHandle); +} + +void LowLevelFile::open (char const * filename) +{ + assert (mHandle == -1); + +#ifdef O_BINARY + static const int openFlags = O_RDONLY | O_BINARY; +#else + static const int openFlags = O_RDONLY; +#endif + + mHandle = ::open (filename, openFlags, 0); + + if (mHandle == -1) + { + std::ostringstream os; + os << "Failed to open '" << filename << "' for reading."; + throw std::runtime_error (os.str ()); + } +} + +void LowLevelFile::close () +{ + assert (mHandle != -1); + + ::close (mHandle); + + mHandle = -1; +} + +size_t LowLevelFile::size () +{ + assert (mHandle != -1); + + size_t oldPosition = ::lseek (mHandle, 0, SEEK_CUR); + + if (oldPosition == size_t (-1)) + throw std::runtime_error ("A query operation on a file failed."); + + size_t Size = ::lseek (mHandle, 0, SEEK_END); + + if (Size == size_t (-1)) + throw std::runtime_error ("A query operation on a file failed."); + + if (lseek (mHandle, oldPosition, SEEK_SET) == -1) + throw std::runtime_error ("A query operation on a file failed."); + + return Size; +} + +void LowLevelFile::seek (size_t Position) +{ + assert (mHandle != -1); + + if (::lseek (mHandle, Position, SEEK_SET) == -1) + throw std::runtime_error ("A seek operation on a file failed."); +} + +size_t LowLevelFile::tell () +{ + assert (mHandle != -1); + + size_t Position = ::lseek (mHandle, 0, SEEK_CUR); + + if (Position == size_t (-1)) + throw std::runtime_error ("A query operation on a file failed."); + + return Position; +} + +size_t LowLevelFile::read (void * data, size_t size) +{ + assert (mHandle != -1); + + int amount = ::read (mHandle, data, size); + + if (amount == -1) + throw std::runtime_error ("A read operation on a file failed."); + + return amount; +} + +#elif FILE_API == FILE_API_WIN32 +/* + * + * Implementation of LowLevelFile methods using Win32 API calls + * + */ + +LowLevelFile::LowLevelFile () +{ + mHandle = INVALID_HANDLE_VALUE; +} + +LowLevelFile::~LowLevelFile () +{ + if (mHandle == INVALID_HANDLE_VALUE) + CloseHandle (mHandle); +} + +void LowLevelFile::open (char const * filename) +{ + assert (mHandle == INVALID_HANDLE_VALUE); + + HANDLE handle = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + + if (handle == NULL) + { + std::ostringstream os; + os << "Failed to open '" << filename << "' for reading."; + throw std::runtime_error (os.str ()); + } + + mHandle = handle; +} + +void LowLevelFile::close () +{ + assert (mHandle != INVALID_HANDLE_VALUE); + + CloseHandle (mHandle); + + mHandle = INVALID_HANDLE_VALUE; +} + +size_t LowLevelFile::size () +{ + assert (mHandle != INVALID_HANDLE_VALUE); + + BY_HANDLE_FILE_INFORMATION info; + + if (!GetFileInformationByHandle (mHandle, &info)) + throw std::runtime_error ("A query operation on a file failed."); + + if (info.nFileSizeHigh != 0) + throw std::runtime_error ("Files greater that 4GB are not supported."); + + return info.nFileSizeLow; +} + +void LowLevelFile::seek (size_t Position) +{ + assert (mHandle != INVALID_HANDLE_VALUE); + + if (SetFilePointer (mHandle, Position, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER) + if (GetLastError () != NO_ERROR) + throw std::runtime_error ("A seek operation on a file failed."); +} + +size_t LowLevelFile::tell () +{ + assert (mHandle != INVALID_HANDLE_VALUE); + + DWORD value = SetFilePointer (mHandle, 0, NULL, SEEK_CUR); + + if (value == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) + throw std::runtime_error ("A query operation on a file failed."); + + return value; +} + +size_t LowLevelFile::read (void * data, size_t size) +{ + assert (mHandle != INVALID_HANDLE_VALUE); + + DWORD read; + + if (!ReadFile (mHandle, data, size, &read, NULL)) + throw std::runtime_error ("A read operation on a file failed."); + + return read; +} + +#endif diff --git a/components/files/lowlevelfile.hpp b/components/files/lowlevelfile.hpp new file mode 100644 index 000000000..a6de6df76 --- /dev/null +++ b/components/files/lowlevelfile.hpp @@ -0,0 +1,54 @@ +#ifndef COMPONENTS_FILES_LOWLEVELFILE_HPP +#define COMPONENTS_FILES_LOWLEVELFILE_HPP + +#include + +#define FILE_API_STDIO 0 +#define FILE_API_POSIX 1 +#define FILE_API_WIN32 2 + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +#define FILE_API FILE_API_POSIX +#elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32 +#define FILE_API FILE_API_WIN32 +#else +#define FILE_API FILE_API_STDIO +#endif + +#if FILE_API == FILE_API_STDIO +#include +#elif FILE_API == FILE_API_POSIX +#elif FILE_API == FILE_API_WIN32 +#include +#else +#error Unsupported File API +#endif + +class LowLevelFile +{ +public: + + LowLevelFile (); + ~LowLevelFile (); + + void open (char const * filename); + void close (); + + size_t size (); + + void seek (size_t Position); + size_t tell (); + + size_t read (void * data, size_t size); + +private: +#if FILE_API == FILE_API_STDIO + FILE* mHandle; +#elif FILE_API == FILE_API_POSIX + int mHandle; +#elif FILE_API == FILE_API_WIN32 + HANDLE mHandle; +#endif +}; + +#endif From fec9a5923767747e9d845ac84cbadc60342e7da5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 1 Jan 2013 15:13:36 -0800 Subject: [PATCH 247/916] changed EMSLoader to use ConstrainedDataStream Changed the EMSLoader class to use the ConstrainedDataStream so that future changes may benifit from its increased performance. --- components/esm/esmreader.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 580e006df..62078977e 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -1,6 +1,8 @@ #include "esmreader.hpp" #include +#include "../files/constrainedfiledatastream.hpp" + namespace ESM { @@ -108,16 +110,12 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) void ESMReader::open(const std::string &file) { - std::ifstream *stream = OGRE_NEW_T(std::ifstream, Ogre::MEMCATEGORY_GENERAL)(file.c_str(), std::ios_base::binary); - // Ogre will delete the stream for us - open(Ogre::DataStreamPtr(new Ogre::FileStreamDataStream(stream)), file); + open (openConstrainedFileDataStream (file.c_str ()), file); } void ESMReader::openRaw(const std::string &file) { - std::ifstream *stream = OGRE_NEW_T(std::ifstream, Ogre::MEMCATEGORY_GENERAL)(file.c_str(), std::ios_base::binary); - // Ogre will delete the stream for us - openRaw(Ogre::DataStreamPtr(new Ogre::FileStreamDataStream(stream)), file); + openRaw (openConstrainedFileDataStream (file.c_str ()), file); } int64_t ESMReader::getHNLong(const char *name) From b4d63814cc13bcd0ef9d46682b73b0f36dad2d0f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 4 Jan 2013 23:12:56 +0100 Subject: [PATCH 248/916] post merge fix --- components/files/lowlevelfile.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/files/lowlevelfile.hpp b/components/files/lowlevelfile.hpp index a6de6df76..f49c466a5 100644 --- a/components/files/lowlevelfile.hpp +++ b/components/files/lowlevelfile.hpp @@ -3,6 +3,8 @@ #include +#include + #define FILE_API_STDIO 0 #define FILE_API_POSIX 1 #define FILE_API_WIN32 2 From 1d4d67f81153fc9a299158daa20b161bb9add69a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 15:03:57 -0800 Subject: [PATCH 249/916] Avoid underflows if the texture name doesn't include a '.' --- components/nifogre/ogre_nif_loader.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index ae2a0ae15..93f00b178 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -537,14 +537,11 @@ static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &nam * textures from tga to dds for increased load speed, but all * texture file name references were kept as .tga. */ - - static const char * path = "textures\\"; + static const char path[] = "textures\\"; texName = path + st->filename; - Ogre::String::size_type pos = texName.rfind('.'); - - if (texName.compare (pos, texName.size () - pos, ".dds") != 0) + if(pos != Ogre::String::npos && texName.compare(pos, texName.length() - pos, ".dds") != 0) { // since we know all (GOTY edition or less) textures end // in .dds, we change the extension From b52904a6ea4f9acd5f76a89a1eecabd27fc5562c Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 4 Jan 2013 19:47:24 -0400 Subject: [PATCH 250/916] Include headers necessary for compilation under VS2010 --- components/files/constrainedfiledatastream.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp index 2f75ce41b..9e36f9075 100644 --- a/components/files/constrainedfiledatastream.cpp +++ b/components/files/constrainedfiledatastream.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace { From a3d33db4153c26f17dfc632551e09c2b62226f29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 15:55:47 -0800 Subject: [PATCH 251/916] Store a NiNode's NiTextKeyExtraData in a user object binding on Ogre::Bone --- components/nifogre/ogre_nif_loader.cpp | 78 +++++++++++++++++--------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 93f00b178..badadfe01 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -49,10 +49,21 @@ typedef unsigned char ubyte; -using namespace std; -using namespace Nif; -using namespace NifOgre; +namespace Nif +{ +// These operators allow the Nif extra data types to be stored in an Ogre::Any +// object, which can then be stored in user object bindings on the nodes + +// TODO: Do something useful +std::ostream& operator<<(std::ostream &o, const Nif::NiTextKeyExtraData&) +{ return o; } + +} // namespace Nif + + +namespace NifOgre +{ // Helper class that computes the bounding box and of a mesh class BoundsFinder @@ -63,7 +74,7 @@ class BoundsFinder MaxMinFinder() { - min = numeric_limits::infinity(); + min = std::numeric_limits::infinity(); max = -min; } @@ -198,6 +209,17 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectornext; } + Nif::ExtraPtr e = node->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiTextKeyExtraData) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + bone->getUserObjectBindings().setUserAny(tk->recName, Ogre::Any(*tk)); + } + e = e->extra; + } + const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { @@ -270,16 +292,16 @@ void loadResource(Ogre::Resource *resource) Nif::NiKeyframeData *kf = kfc->data.getPtr(); /* Get the keyframes and make sure they're sorted first to last */ - QuaternionKeyList quatkeys = kf->mRotations; - Vector3KeyList trankeys = kf->mTranslations; - FloatKeyList scalekeys = kf->mScales; + Nif::QuaternionKeyList quatkeys = kf->mRotations; + Nif::Vector3KeyList trankeys = kf->mTranslations; + Nif::FloatKeyList scalekeys = kf->mScales; std::sort(quatkeys.mKeys.begin(), quatkeys.mKeys.end(), KeyTimeSort()); std::sort(trankeys.mKeys.begin(), trankeys.mKeys.end(), KeyTimeSort()); std::sort(scalekeys.mKeys.begin(), scalekeys.mKeys.end(), KeyTimeSort()); - QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); Ogre::Bone *bone = skel->getBone(targets[i]); const Ogre::Quaternion startquat = bone->getInitialOrientation(); @@ -347,7 +369,7 @@ void loadResource(Ogre::Resource *resource) kframe->setRotation(curquat); else { - QuaternionKeyList::VecType::const_iterator last = quatiter-1; + Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); } @@ -355,7 +377,7 @@ void loadResource(Ogre::Resource *resource) kframe->setTranslate(curtrans); else { - Vector3KeyList::VecType::const_iterator last = traniter-1; + Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); } @@ -363,7 +385,7 @@ void loadResource(Ogre::Resource *resource) kframe->setScale(curscale); else { - FloatKeyList::VecType::const_iterator last = scaleiter-1; + Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); kframe->setScale(lastscale + ((curscale-lastscale)*diff)); } @@ -485,7 +507,7 @@ static void fail(const std::string &msg) public: -static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &name, const Ogre::String &group) +static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -505,24 +527,24 @@ static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &nam bool vertexColour = (shape->data->colors.size() != 0); // These are set below if present - const NiTexturingProperty *t = NULL; - const NiMaterialProperty *m = NULL; - const NiAlphaProperty *a = NULL; + const Nif::NiTexturingProperty *t = NULL; + const Nif::NiMaterialProperty *m = NULL; + const Nif::NiAlphaProperty *a = NULL; // Scan the property list for material information - const PropertyList &list = shape->props; + const Nif::PropertyList &list = shape->props; for (size_t i = 0;i < list.length();i++) { // Entries may be empty if (list[i].empty()) continue; - const Property *pr = list[i].getPtr(); - if (pr->recType == RC_NiTexturingProperty) - t = static_cast(pr); - else if (pr->recType == RC_NiMaterialProperty) - m = static_cast(pr); - else if (pr->recType == RC_NiAlphaProperty) - a = static_cast(pr); + const Nif::Property *pr = list[i].getPtr(); + if (pr->recType == Nif::RC_NiTexturingProperty) + t = static_cast(pr); + else if (pr->recType == Nif::RC_NiMaterialProperty) + m = static_cast(pr); + else if (pr->recType == Nif::RC_NiAlphaProperty) + a = static_cast(pr); else warn("Skipped property type: "+pr->recName); } @@ -530,7 +552,7 @@ static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &nam // Texture if (t && t->textures[0].inUse) { - NiSourceTexture *st = t->textures[0].texture.getPtr(); + Nif::NiSourceTexture *st = t->textures[0].texture.getPtr(); if (st->external) { /* Bethesda at some at some point converted all their BSA @@ -991,7 +1013,7 @@ public: if(node->recType == Nif::RC_NiTriShape) { - const NiTriShape *shape = dynamic_cast(node); + const Nif::NiTriShape *shape = dynamic_cast(node); Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@shape="+shape->name; @@ -1220,3 +1242,5 @@ extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height, */ + +} // nsmaepace NifOgre From 683ced54a09eefd8dc38f8d64341a30d289f45a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 19:41:37 -0800 Subject: [PATCH 252/916] Store and retrieve the node text keys in the bones' user object bindings --- components/nifogre/ogre_nif_loader.cpp | 67 +++++++++++++------------- components/nifogre/ogre_nif_loader.hpp | 2 +- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index badadfe01..6ee02438a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -49,22 +49,20 @@ typedef unsigned char ubyte; -namespace Nif +namespace std { -// These operators allow the Nif extra data types to be stored in an Ogre::Any +// These operators allow extra data types to be stored in an Ogre::Any // object, which can then be stored in user object bindings on the nodes // TODO: Do something useful -std::ostream& operator<<(std::ostream &o, const Nif::NiTextKeyExtraData&) +ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) { return o; } -} // namespace Nif - +} namespace NifOgre { - // Helper class that computes the bounding box and of a mesh class BoundsFinder { @@ -164,8 +162,9 @@ static void fail(const std::string &msg) } -static void insertTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap *textkeys) +static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) { + TextKeyMap textkeys; for(size_t i = 0;i < tk->list.size();i++) { const std::string &str = tk->list[i].text; @@ -178,11 +177,12 @@ static void insertTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap *textke break; std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - textkeys->insert(std::make_pair(tk->list[i].time, str.substr(pos, nextpos-pos))); + textkeys.insert(std::make_pair(tk->list[i].time, str.substr(pos, nextpos-pos))); pos = nextpos; } } + return textkeys; } @@ -215,7 +215,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorrecType == Nif::RC_NiTextKeyExtraData) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - bone->getUserObjectBindings().setUserAny(tk->recName, Ogre::Any(*tk)); + bone->getUserObjectBindings().setUserAny("TextKeyExtraData", Ogre::Any(extractTextKeys(tk))); } e = e->extra; } @@ -394,35 +394,18 @@ void loadResource(Ogre::Resource *resource) anim->optimise(); } -bool createSkeleton(const std::string &name, const std::string &group, TextKeyMap *textkeys, const Nif::Node *node) +bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { - if(textkeys) - { - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - insertTextKeys(tk, textkeys); - } - e = e->extra; - } - } - if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(name); if(skel.isNull()) { NIFSkeletonLoader *loader = &sLoaders[name]; skel = skelMgr.create(name, group, true, loader); } - - if(!textkeys || textkeys->size() > 0) - return true; + return true; } const Nif::NiNode *ninode = dynamic_cast(node); @@ -433,7 +416,7 @@ bool createSkeleton(const std::string &name, const std::string &group, TextKeyMa { if(!children[i].empty()) { - if(createSkeleton(name, group, textkeys, children[i].getPtr())) + if(createSkeleton(name, group, children[i].getPtr())) return true; } } @@ -1057,7 +1040,7 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -MeshPairList NIFLoader::load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group) +MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group) { MeshPairList meshes; @@ -1084,7 +1067,7 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, TextKeyMap } NIFSkeletonLoader skelldr; - bool hasSkel = skelldr.createSkeleton(skelName, group, textkeys, node); + bool hasSkel = skelldr.createSkeleton(skelName, group, node); NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); @@ -1096,7 +1079,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke { EntityList entitylist; - MeshPairList meshes = load(name, name, textkeys, group); + MeshPairList meshes = load(name, name, group); if(meshes.size() == 0) return entitylist; @@ -1109,6 +1092,24 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke entitylist.mSkelBase = entity; } + if(entitylist.mSkelBase) + { + // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + Ogre::SkeletonPtr skel = skelMgr.getByName(entitylist.mSkelBase->getSkeleton()->getName()); + Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); + while(iter.hasMoreElements()) + { + Ogre::Bone *bone = iter.getNext(); + const Ogre::Any &data = bone->getUserObjectBindings().getUserAny("TextKeyExtraData"); + if(!data.isEmpty()) + { + *textkeys = Ogre::any_cast(data); + break; + } + } + } + if(entitylist.mSkelBase) { parent->attachObject(entitylist.mSkelBase); @@ -1140,7 +1141,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo { EntityList entitylist; - MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), NULL, group); + MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); if(meshes.size() == 0) return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 74b6f44df..3e05c5873 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -69,7 +69,7 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group); + static MeshPairList load(std::string name, std::string skelName, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From 917bbc4e110672e8c0ef7bc8ea8d6282213fdeed Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 5 Jan 2013 00:26:33 -0400 Subject: [PATCH 253/916] Create static and non-discardable textures with the right parameters (should fix Issue 443) --- libs/openengine/ogre/imagerotate.cpp | 21 ++++++++++++++++++--- libs/openengine/ogre/renderer.cpp | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp index 11fd5eea6..3dd584078 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/libs/openengine/ogre/imagerotate.cpp @@ -16,6 +16,8 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest { Root* root = Ogre::Root::getSingletonPtr(); + std::string destImageRot = std::string(destImage) + std::string("_rot"); + SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); Camera* camera = sceneMgr->createCamera("ImageRotateCamera"); @@ -48,8 +50,8 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest unsigned int width = sourceTexture->getWidth(); unsigned int height = sourceTexture->getHeight(); - TexturePtr destTexture = TextureManager::getSingleton().createManual( - destImage, + TexturePtr destTextureRot = TextureManager::getSingleton().createManual( + destImageRot, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, width, height, @@ -57,7 +59,7 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest PF_FLOAT16_RGBA, TU_RENDERTARGET); - RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); + RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget(); rtt->setAutoUpdated(false); Viewport* vp = rtt->addViewport(camera); vp->setOverlaysEnabled(false); @@ -66,7 +68,20 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest rtt->update(); + //copy the rotated image to a static texture + TexturePtr destTexture = TextureManager::getSingleton().createManual( + destImage, + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + width, height, + 0, + PF_FLOAT16_RGBA, + Ogre::TU_STATIC); + + destTexture->getBuffer()->blit(destTextureRot->getBuffer()); + // remove all the junk we've created + TextureManager::getSingleton().remove(destImageRot); MaterialManager::getSingleton().remove("ImageRotateMaterial"); root->destroySceneManager(sceneMgr); delete rect; diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 87ebe1139..3cdb00518 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -226,7 +226,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& 1, 1, 0, Ogre::PF_A8R8G8B8, - Ogre::TU_DYNAMIC_WRITE_ONLY); + Ogre::TU_WRITE_ONLY); } void OgreRenderer::createScene(const std::string& camName, float fov, float nearClip) From 3131e8dae6de127c4d3c8ed95c773b56442da92f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 20:33:26 -0800 Subject: [PATCH 254/916] Don't get the text keys if they're not being requested --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 6ee02438a..27e4e7440 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1092,7 +1092,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke entitylist.mSkelBase = entity; } - if(entitylist.mSkelBase) + if(entitylist.mSkelBase && textkeys) { // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); From 8a086e3afbc510d70c66955c19a99d44b797bed7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 20:58:35 -0800 Subject: [PATCH 255/916] Cache the mesh names from the mesh/skeleton pairs --- components/nifogre/ogre_nif_loader.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 27e4e7440..31d873489 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1040,13 +1040,19 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; +typedef std::map MeshPairMap; +static MeshPairMap sMeshPairMap; + MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group) { - MeshPairList meshes; - std::transform(name.begin(), name.end(), name.begin(), ::tolower); std::transform(skelName.begin(), skelName.end(), skelName.begin(), ::tolower); + MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName); + if(meshiter != sMeshPairMap.end()) + return meshiter->second; + + MeshPairList &meshes = sMeshPairMap[name+"@skel="+skelName]; Nif::NIFFile nif(name); if (nif.numRecords() < 1) { @@ -1067,7 +1073,7 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: } NIFSkeletonLoader skelldr; - bool hasSkel = skelldr.createSkeleton(skelName, group, node); + bool hasSkel = skelldr.createSkeleton(name, group, node); NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); From 3ed77ca1890b90c9c1d9fe7a4cddbfea1e06933b Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 5 Jan 2013 01:17:07 -0400 Subject: [PATCH 256/916] Include C++ header instead --- components/files/constrainedfiledatastream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp index 9e36f9075..63bd3490f 100644 --- a/components/files/constrainedfiledatastream.cpp +++ b/components/files/constrainedfiledatastream.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace { From 6e84d4bcdde03b821c6d880bda2d26b4dfbdf207 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 4 Jan 2013 23:19:48 -0800 Subject: [PATCH 257/916] Add a helper method to load entity objects --- apps/openmw/mwrender/animation.cpp | 30 +++++++++++++++++++--- apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/creatureanimation.cpp | 15 +---------- apps/openmw/mwrender/npcanimation.cpp | 17 +----------- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2a3b8cf43..4784771a9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -19,10 +19,34 @@ Animation::Animation() Animation::~Animation() { - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) - sceneMgr->destroyEntity(mEntityList.mEntities[i]); + if(mInsert) + { + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) + sceneMgr->destroyEntity(mEntityList.mEntities[i]); + } mEntityList.mEntities.clear(); + mEntityList.mSkelBase = NULL; +} + + +void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) +{ + mInsert = node; + assert(mInsert); + + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, model); + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setEnabled(true); + state->setLoop(false); + } + } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 07583db78..ebbfb2a7a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -43,6 +43,8 @@ protected: bool findGroupTimes(const std::string &groupname, GroupTimes *times); + void createEntityList(Ogre::SceneNode *node, const std::string &model); + public: Animation(); virtual ~Animation(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7ee361a6f..1ca897c15 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -18,7 +18,6 @@ CreatureAnimation::~CreatureAnimation() CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() { - mInsert = ptr.getRefData().getBaseNode(); MWWorld::LiveCellRef *ref = ptr.get(); assert (ref->mBase != NULL); @@ -26,7 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() { std::string mesh = "meshes\\" + ref->mBase->mModel; - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, mesh); + createEntityList(ptr.getRefData().getBaseNode(), mesh); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; @@ -52,18 +51,6 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() } ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } - - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); - state->setLoop(false); - } - } } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e6a8006e2..c76c67425 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -82,13 +82,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mBodyPrefix = "b_n_" + mNpc->mRace; std::transform(mBodyPrefix.begin(), mBodyPrefix.end(), mBodyPrefix.begin(), ::tolower); - mInsert = node; - assert(mInsert); - bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, smodel); + createEntityList(node, smodel); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *base = mEntityList.mEntities[i]; @@ -116,18 +113,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); - state->setLoop(false); - } - } - float scale = race->mData.mHeight.mMale; if (!mNpc->isMale()) { scale = race->mData.mHeight.mFemale; From 818a24cdd6542513d7b3f4133856cdc338b23822 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 00:03:14 -0800 Subject: [PATCH 258/916] Hold on to the AnimationState being used for animating --- apps/openmw/mwrender/animation.cpp | 15 +++++---------- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4784771a9..6b8a3283c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -14,6 +14,7 @@ Animation::Animation() : mInsert(NULL) , mTime(0.0f) , mSkipFrame(false) + , mAnimState(NULL) { } @@ -45,6 +46,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::AnimationState *state = as.getNext(); state->setEnabled(true); state->setLoop(false); + if(!mAnimState) + mAnimState = state; } } } @@ -155,16 +158,8 @@ void Animation::runAnimation(float timepassed) } } - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setTimePosition(mTime); - } - } + if(mAnimState) + mAnimState->setTimePosition(mTime); } mSkipFrame = false; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ebbfb2a7a..de4778d87 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -40,6 +40,7 @@ protected: NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; + Ogre::AnimationState *mAnimState; bool findGroupTimes(const std::string &groupname, GroupTimes *times); From 761914bdaa3d02207afe13fbf36a3d3430fe8226 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 03:31:51 -0800 Subject: [PATCH 259/916] Use a separate method to build the animation --- components/nifogre/ogre_nif_loader.cpp | 228 +++++++++++++------------ 1 file changed, 115 insertions(+), 113 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 31d873489..61e3a72e9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -162,6 +162,120 @@ static void fail(const std::string &msg) } +static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) +{ + Ogre::Animation *anim = skel->createAnimation(name, stopTime); + /* HACK: Pre-create the node tracks by matching the track IDs with the + * bone IDs. Otherwise, Ogre animates the wrong bones. */ + size_t bonecount = skel->getNumBones(); + for(size_t i = 0;i < bonecount;i++) + anim->createNodeTrack(i, skel->getBone(i)); + + for(size_t i = 0;i < ctrls.size();i++) + { + Nif::NiKeyframeController *kfc = ctrls[i]; + Nif::NiKeyframeData *kf = kfc->data.getPtr(); + + /* Get the keyframes and make sure they're sorted first to last */ + const Nif::QuaternionKeyList &quatkeys = kf->mRotations; + const Nif::Vector3KeyList &trankeys = kf->mTranslations; + const Nif::FloatKeyList &scalekeys = kf->mScales; + + Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + + Ogre::Bone *bone = skel->getBone(targets[i]); + Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); + const Ogre::Quaternion startquat = bone->getInitialOrientation(); + const Ogre::Vector3 starttrans = bone->getInitialPosition(); + const Ogre::Vector3 startscale = bone->getInitialScale(); + + Ogre::Quaternion lastquat, curquat; + Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); + Ogre::Vector3 lastscale(1.0f), curscale(1.0f); + if(quatiter != quatkeys.mKeys.end()) + lastquat = curquat = startquat.Inverse() * quatiter->mValue; + if(traniter != trankeys.mKeys.end()) + lasttrans = curtrans = traniter->mValue - starttrans; + if(scaleiter != scalekeys.mKeys.end()) + lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + float begTime = std::max(kfc->timeStart, startTime); + float endTime = std::min(kfc->timeStop, stopTime); + bool didlast = false; + + while(!didlast) + { + float curtime = std::numeric_limits::max(); + + //Get latest time + if(quatiter != quatkeys.mKeys.end()) + curtime = std::min(curtime, quatiter->mTime); + if(traniter != trankeys.mKeys.end()) + curtime = std::min(curtime, traniter->mTime); + if(scaleiter != scalekeys.mKeys.end()) + curtime = std::min(curtime, scaleiter->mTime); + + curtime = std::max(curtime, begTime); + if(curtime >= endTime) + { + didlast = true; + curtime = endTime; + } + + // Get the latest quaternions, translations, and scales for the + // current time + while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) + { + lastquat = curquat; + if(++quatiter != quatkeys.mKeys.end()) + curquat = startquat.Inverse() * quatiter->mValue; + } + while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) + { + lasttrans = curtrans; + if(++traniter != trankeys.mKeys.end()) + curtrans = traniter->mValue - starttrans; + } + while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) + { + lastscale = curscale; + if(++scaleiter != scalekeys.mKeys.end()) + curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + } + + Ogre::TransformKeyFrame *kframe; + kframe = nodetrack->createNodeKeyFrame(curtime); + if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) + kframe->setRotation(curquat); + else + { + Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; + float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); + kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); + } + if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) + kframe->setTranslate(curtrans); + else + { + Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; + float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); + kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); + } + if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) + kframe->setScale(curscale); + else + { + Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; + float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); + kframe->setScale(lastscale + ((curscale-lastscale)*diff)); + } + } + } + anim->optimise(); +} + + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) { TextKeyMap textkeys; @@ -279,119 +393,7 @@ void loadResource(Ogre::Resource *resource) return; } - Ogre::Animation *anim = skel->createAnimation(skel->getName(), maxtime); - /* HACK: Pre-create the node tracks by matching the track IDs with the - * bone IDs. Otherwise, Ogre animates the wrong bones. */ - size_t bonecount = skel->getNumBones(); - for(size_t i = 0;i < bonecount;i++) - anim->createNodeTrack(i, skel->getBone(i)); - - for(size_t i = 0;i < ctrls.size();i++) - { - Nif::NiKeyframeController *kfc = ctrls[i]; - Nif::NiKeyframeData *kf = kfc->data.getPtr(); - - /* Get the keyframes and make sure they're sorted first to last */ - Nif::QuaternionKeyList quatkeys = kf->mRotations; - Nif::Vector3KeyList trankeys = kf->mTranslations; - Nif::FloatKeyList scalekeys = kf->mScales; - std::sort(quatkeys.mKeys.begin(), quatkeys.mKeys.end(), KeyTimeSort()); - std::sort(trankeys.mKeys.begin(), trankeys.mKeys.end(), KeyTimeSort()); - std::sort(scalekeys.mKeys.begin(), scalekeys.mKeys.end(), KeyTimeSort()); - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - - Ogre::Bone *bone = skel->getBone(targets[i]); - const Ogre::Quaternion startquat = bone->getInitialOrientation(); - const Ogre::Vector3 starttrans = bone->getInitialPosition(); - const Ogre::Vector3 startscale = bone->getInitialScale(); - Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); - - Ogre::Quaternion lastquat, curquat; - Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); - Ogre::Vector3 lastscale(1.0f), curscale(1.0f); - if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = startquat.Inverse() * quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue - starttrans; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; - bool didlast = false; - - while(!didlast) - { - float curtime = kfc->timeStop; - - //Get latest time - if(quatiter != quatkeys.mKeys.end()) - curtime = std::min(curtime, quatiter->mTime); - if(traniter != trankeys.mKeys.end()) - curtime = std::min(curtime, traniter->mTime); - if(scaleiter != scalekeys.mKeys.end()) - curtime = std::min(curtime, scaleiter->mTime); - - curtime = std::max(curtime, kfc->timeStart); - if(curtime >= kfc->timeStop) - { - didlast = true; - curtime = kfc->timeStop; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - quatiter++; - if(quatiter != quatkeys.mKeys.end()) - curquat = startquat.Inverse() * quatiter->mValue ; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - traniter++; - if(traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue - starttrans; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - scaleiter++; - if(scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue) / startscale; - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; - float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); - kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); - } - if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) - kframe->setTranslate(curtrans); - else - { - Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; - float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); - kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); - } - if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) - kframe->setScale(curscale); - else - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); + buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); } bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) From 58d35dbfcfef078f388cdf28dc1bd339df8fb3e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 04:01:11 -0800 Subject: [PATCH 260/916] Have createEntities' caller retrieve the text keys as needed --- apps/openmw/mwrender/animation.cpp | 19 ++++++++++++++-- apps/openmw/mwrender/objects.cpp | 2 +- components/nifogre/ogre_nif_loader.cpp | 30 ++++++-------------------- components/nifogre/ogre_nif_loader.hpp | 4 ++-- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6b8a3283c..d2d253b91 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,6 +1,6 @@ #include "animation.hpp" -#include +#include #include #include #include @@ -36,7 +36,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mInsert = node; assert(mInsert); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, model); + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); @@ -49,6 +49,21 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!mAnimState) mAnimState = state; } + + // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + Ogre::SkeletonPtr skel = skelMgr.getByName(mEntityList.mSkelBase->getSkeleton()->getName()); + Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); + while(iter.hasMoreElements()) + { + Ogre::Bone *bone = iter.getNext(); + const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); + if(!data.isEmpty()) + { + mTextKeys = Ogre::any_cast(data); + break; + } + } } } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 36f09e6d9..ae188c11e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -94,7 +94,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, NULL, mesh); + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) { const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 61e3a72e9..f579b4b93 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -329,7 +329,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorrecType == Nif::RC_NiTextKeyExtraData) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - bone->getUserObjectBindings().setUserAny("TextKeyExtraData", Ogre::Any(extractTextKeys(tk))); + bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(extractTextKeys(tk))); } e = e->extra; } @@ -1083,7 +1083,7 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textkeys, const std::string &name, const std::string &group) +EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group) { EntityList entitylist; @@ -1091,7 +1091,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke if(meshes.size() == 0) return entitylist; - Ogre::SceneManager *sceneMgr = parent->getCreator(); + Ogre::SceneManager *sceneMgr = parentNode->getCreator(); for(size_t i = 0;i < meshes.size();i++) { entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first)); @@ -1100,34 +1100,16 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke entitylist.mSkelBase = entity; } - if(entitylist.mSkelBase && textkeys) - { - // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(entitylist.mSkelBase->getSkeleton()->getName()); - Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); - while(iter.hasMoreElements()) - { - Ogre::Bone *bone = iter.getNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny("TextKeyExtraData"); - if(!data.isEmpty()) - { - *textkeys = Ogre::any_cast(data); - break; - } - } - } - if(entitylist.mSkelBase) { - parent->attachObject(entitylist.mSkelBase); + parentNode->attachObject(entitylist.mSkelBase); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity != entitylist.mSkelBase && entity->hasSkeleton()) { entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - parent->attachObject(entity); + parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); @@ -1136,7 +1118,7 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textke else { for(size_t i = 0;i < entitylist.mEntities.size();i++) - parent->attachObject(entitylist.mEntities[i]); + parentNode->attachObject(entitylist.mEntities[i]); } return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 3e05c5873..9dcd0bea6 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -43,6 +43,7 @@ namespace NifOgre // FIXME: These should not be in NifOgre, it works agnostic of what model format is used typedef std::multimap TextKeyMap; +static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { std::vector mEntities; Ogre::Entity *mSkelBase; @@ -77,8 +78,7 @@ public: const std::string &name, const std::string &group="General"); - static EntityList createEntities(Ogre::SceneNode *parent, - TextKeyMap *textkeys, + static EntityList createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group="General"); }; From e5ce55b6a4b4a88d75203c5c73b832310b0757aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 06:20:21 -0800 Subject: [PATCH 261/916] Remove a hack --- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index f579b4b93..870b8df0e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -165,11 +165,6 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { Ogre::Animation *anim = skel->createAnimation(name, stopTime); - /* HACK: Pre-create the node tracks by matching the track IDs with the - * bone IDs. Otherwise, Ogre animates the wrong bones. */ - size_t bonecount = skel->getNumBones(); - for(size_t i = 0;i < bonecount;i++) - anim->createNodeTrack(i, skel->getBone(i)); for(size_t i = 0;i < ctrls.size();i++) { @@ -186,10 +181,12 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); Ogre::Bone *bone = skel->getBone(targets[i]); - Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); - const Ogre::Quaternion startquat = bone->getInitialOrientation(); - const Ogre::Vector3 starttrans = bone->getInitialPosition(); - const Ogre::Vector3 startscale = bone->getInitialScale(); + // NOTE: For some reason, Ogre doesn't like the node track ID being different from + // the bone ID + Ogre::NodeAnimationTrack *nodetrack = anim->createNodeTrack(bone->getHandle(), bone); + const Ogre::Quaternion &startquat = bone->getInitialOrientation(); + const Ogre::Vector3 &starttrans = bone->getInitialPosition(); + const Ogre::Vector3 &startscale = bone->getInitialScale(); Ogre::Quaternion lastquat, curquat; Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); From 63f09462fd1395f1550df11eb400e0e81959c14b Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 6 Jan 2013 01:37:58 +0100 Subject: [PATCH 262/916] to_utf8, Utf8Encoder: pass encoding as constructor parameter Edit other files accordingly. --- apps/esmtool/esmtool.cpp | 25 ++++++++----------------- apps/launcher/model/datafilesmodel.cpp | 6 ++++-- apps/mwiniimporter/importer.cpp | 3 +-- apps/openmw/engine.cpp | 7 +++++-- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 2 +- components/esm/esmreader.cpp | 7 +++---- components/esm/esmreader.hpp | 7 +++---- components/esm/esmwriter.cpp | 20 +++----------------- components/esm/esmwriter.hpp | 8 +++----- components/to_utf8/to_utf8.cpp | 10 ++-------- components/to_utf8/to_utf8.hpp | 6 +----- components/translation/translation.cpp | 7 +++---- components/translation/translation.hpp | 5 ++--- 14 files changed, 41 insertions(+), 76 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 0cd6e3905..fbfc884d7 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -165,23 +165,12 @@ bool parseOptions (int argc, char** argv, Arguments &info) // Font encoding settings info.encoding = variables["encoding"].as(); - if (info.encoding == "win1250") + if(info.encoding != "win1250" && info.encoding != "win1251" && info.encoding != "win1252") { - std::cout << "Using Central and Eastern European font encoding." << std::endl; - } - else if (info.encoding == "win1251") - { - std::cout << "Using Cyrillic font encoding." << std::endl; - } - else - { - if(info.encoding != "win1252") - { - std::cout << info.encoding << " is not a valid encoding option." << std::endl; - info.encoding = "win1252"; - } - std::cout << "Using default (English) font encoding." << std::endl; + std::cout << info.encoding << " is not a valid encoding option." << std::endl; + info.encoding = "win1252"; } + std::cout << ToUTF8::encodingUsingMessage(info.encoding) << std::endl; return true; } @@ -262,7 +251,8 @@ void printRaw(ESM::ESMReader &esm) int load(Arguments& info) { ESM::ESMReader& esm = info.reader; - esm.setEncoding(ToUTF8::calculateEncoding(info.encoding)); + ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); + esm.setEncoder(&encoder); std::string filename = info.filename; std::cout << "Loading file: " << filename << std::endl; @@ -432,7 +422,8 @@ int clone(Arguments& info) std::cout << std::endl << "Saving records to: " << info.outname << "..." << std::endl; ESM::ESMWriter& esm = info.writer; - esm.setEncoding(info.encoding); + ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); + esm.setEncoder(&encoder); esm.setAuthor(info.data.author); esm.setDescription(info.data.description); esm.setVersion(info.data.version); diff --git a/apps/launcher/model/datafilesmodel.cpp b/apps/launcher/model/datafilesmodel.cpp index 716c9e902..e84dbe0ac 100644 --- a/apps/launcher/model/datafilesmodel.cpp +++ b/apps/launcher/model/datafilesmodel.cpp @@ -272,7 +272,8 @@ void DataFilesModel::addMasters(const QString &path) foreach (const QString &path, dir.entryList()) { try { ESM::ESMReader fileReader; - fileReader.setEncoding(ToUTF8::calculateEncoding(mEncoding.toStdString())); + ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString())); + fileReader.setEncoder(&encoder); fileReader.open(dir.absoluteFilePath(path).toStdString()); ESM::ESMReader::MasterList mlist = fileReader.getMasters(); @@ -335,7 +336,8 @@ void DataFilesModel::addPlugins(const QString &path) try { ESM::ESMReader fileReader; - fileReader.setEncoding(ToUTF8::calculateEncoding(mEncoding.toStdString())); + ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString())); + fileReader.setEncoder(&encoder); fileReader.open(dir.absoluteFilePath(path).toStdString()); ESM::ESMReader::MasterList mlist = fileReader.getMasters(); diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 5c3dedd04..6a7274e0a 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -649,8 +649,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) { std::string section(""); MwIniImporter::multistrmap map; boost::iostreams::streamfile(filename.c_str()); - ToUTF8::Utf8Encoder encoder; - encoder.setEncoding(mEncoding); + ToUTF8::Utf8Encoder encoder(mEncoding); std::string line; while (std::getline(file, line)) { diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e2d28a808..aadeb7f3a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -331,11 +331,15 @@ void OMW::Engine::go() // cursor replacer (converts the cursor from the bsa so they can be used by mygui) MWGui::CursorReplace replacer; + // Create encoder + ToUTF8::Utf8Encoder encoder (mEncoding); + // Create the world mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoding, mFallbackMap)); + mResDir, mCfgMgr.getCachePath(), mNewGame, &encoder, mFallbackMap)); //Load translation data + mTranslationDataStorage.setEncoder(&encoder); mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster); // Create window manager - this manages all the MW-specific GUI windows @@ -494,7 +498,6 @@ void OMW::Engine::showFPS(int level) void OMW::Engine::setEncoding(const ToUTF8::FromType& encoding) { mEncoding = encoding; - mTranslationDataStorage.setEncoding (encoding); } void OMW::Engine::setFallbackValues(std::map fallbackMap) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3995123b0..4f60f6ef4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -170,7 +170,7 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - const ToUTF8::FromType& encoding, std::map fallbackMap) + ToUTF8::Utf8Encoder* encoder, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), mNumFacing(0) @@ -187,7 +187,7 @@ namespace MWWorld std::cout << "Loading ESM " << masterPath.string() << "\n"; // This parses the ESM file and loads a sample cell - mEsm.setEncoding(encoding); + mEsm.setEncoder(encoder); mEsm.open (masterPath.string()); mStore.load (mEsm); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 71ae9597f..d29adebf4 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -95,7 +95,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - const ToUTF8::FromType& encoding, std::map fallbackMap); + ToUTF8::Utf8Encoder* encoder, std::map fallbackMap); virtual ~World(); diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 5cd99a64a..99f7971b1 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -344,7 +344,7 @@ std::string ESMReader::getString(int size) getExact(ptr, size); // Convert to UTF8 and return - return mEncoder.getUtf8(ptr, size); + return mEncoder->getUtf8(ptr, size); } void ESMReader::fail(const std::string &msg) @@ -362,10 +362,9 @@ void ESMReader::fail(const std::string &msg) throw std::runtime_error(ss.str()); } -void ESMReader::setEncoding(const ToUTF8::FromType& encoding) +void ESMReader::setEncoder(ToUTF8::Utf8Encoder* encoder) { - mEncoding = encoding; - mEncoder.setEncoding(encoding); + mEncoder = encoder; } } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 57503aea7..d52be25aa 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -235,8 +235,8 @@ public: /// Used for error handling void fail(const std::string &msg); - /// Sets font encoding for ESM strings - void setEncoding(const ToUTF8::FromType& encoding); + /// Sets font encoder for ESM strings + void setEncoder(ToUTF8::Utf8Encoder* encoder); private: Ogre::DataStreamPtr mEsm; @@ -251,8 +251,7 @@ private: SaveData mSaveData; MasterList mMasters; - ToUTF8::FromType mEncoding; - ToUTF8::Utf8Encoder mEncoder; + ToUTF8::Utf8Encoder* mEncoder; }; } #endif diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index a00c7971d..e2f878a25 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -158,7 +158,7 @@ void ESMWriter::writeHString(const std::string& data) else { // Convert to UTF8 and return - std::string ascii = m_encoder.getLegacyEnc(data); + std::string ascii = m_encoder->getLegacyEnc(data); write(ascii.c_str(), ascii.size()); } @@ -188,23 +188,9 @@ void ESMWriter::write(const char* data, int size) m_stream->write(data, size); } -void ESMWriter::setEncoding(const std::string& encoding) +void ESMWriter::setEncoder(ToUTF8::Utf8Encoder* encoder) { - if (encoding == "win1250") - { - m_encoding = ToUTF8::WINDOWS_1250; - } - else if (encoding == "win1251") - { - m_encoding = ToUTF8::WINDOWS_1251; - } - else - { - // Default Latin encoding - m_encoding = ToUTF8::WINDOWS_1252; - } - - m_encoder.setEncoding(m_encoding); + m_encoder = encoder; } } diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index 20bc5da12..b557a29ad 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -6,7 +6,7 @@ #include #include "esmcommon.hpp" -#include "../to_utf8/to_utf8.hpp" +#include namespace ESM { @@ -24,7 +24,7 @@ public: void setVersion(int ver); int getType(); void setType(int type); - void setEncoding(const std::string& encoding); // Write strings as UTF-8? + void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8? void setAuthor(const std::string& author); void setDescription(const std::string& desc); @@ -94,12 +94,10 @@ private: std::list m_records; std::ostream* m_stream; std::streampos m_headerPos; - ToUTF8::FromType m_encoding; - ToUTF8::Utf8Encoder m_encoder; + ToUTF8::Utf8Encoder* m_encoder; int m_recordCount; HEDRstruct m_header; - SaveData m_saveData; }; } diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 5efec36a4..275f5483f 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -43,16 +43,10 @@ using namespace ToUTF8; -Utf8Encoder::Utf8Encoder(void): +Utf8Encoder::Utf8Encoder(const FromType sourceEncoding): mOutput(50*1024) { -} - -void Utf8Encoder::setEncoding(const FromType sourceEncoding) -{ - mEncoding = sourceEncoding; - - switch (mEncoding) + switch (sourceEncoding) { case ToUTF8::WINDOWS_1252: { diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index bfba8a1ac..e150cf17b 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -24,9 +24,7 @@ namespace ToUTF8 class Utf8Encoder { public: - Utf8Encoder(void); - - void setEncoding(const FromType sourceEncoding); + Utf8Encoder(FromType sourceEncoding); // Convert to UTF8 from the previously given code page. std::string getUtf8(const char *input, int size); @@ -48,9 +46,7 @@ namespace ToUTF8 size_t getLength2(const char* input, bool &ascii); void copyFromArray2(const char*& chp, char* &out); - FromType mEncoding; std::vector mOutput; - int mSize; char* translationArray; }; } diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index 002446e4f..184cf399c 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -50,7 +50,7 @@ namespace Translation if (!line.empty()) { - line = mEncoder.getUtf8(line); + line = mEncoder->getUtf8(line); size_t tab_pos = line.find('\t'); if (tab_pos != std::string::npos && tab_pos > 0 && tab_pos < line.size() - 1) @@ -101,10 +101,9 @@ namespace Translation return phrase; } - void Storage::setEncoding (const ToUTF8::FromType& encoding) + void Storage::setEncoder(ToUTF8::Utf8Encoder* encoder) { - mEncoding = encoding; - mEncoder.setEncoding(encoding); + mEncoder = encoder; } bool Storage::hasTranslation() const diff --git a/components/translation/translation.hpp b/components/translation/translation.hpp index 6c3e4df86..bca9ea255 100644 --- a/components/translation/translation.hpp +++ b/components/translation/translation.hpp @@ -19,7 +19,7 @@ namespace Translation // Standard form usually means nominative case std::string topicStandardForm(const std::string& phrase) const; - void setEncoding (const ToUTF8::FromType& encoding); + void setEncoder(ToUTF8::Utf8Encoder* encoder); bool hasTranslation() const; @@ -34,8 +34,7 @@ namespace Translation void loadDataFromStream(ContainerType& container, std::istream& stream); - ToUTF8::FromType mEncoding; - ToUTF8::Utf8Encoder mEncoder; + ToUTF8::Utf8Encoder* mEncoder; ContainerType mCellNamesTranslations, mTopicIDs, mPhraseForms; }; } From 18389c7b04213bf56987db8fa9b6d29365a090ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 17:50:22 -0800 Subject: [PATCH 263/916] Set non-bone nodes as manually controlled --- components/nifogre/ogre_nif_loader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 870b8df0e..f1aecf720 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -306,11 +306,12 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorcreateBone(); if(parent) parent->addChild(bone); + if(!node->boneTrafo) + bone->setManuallyControlled(true); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); bone->setScale(Ogre::Vector3(node->trafo.scale)); bone->setBindingPose(); - bone->setInitialState(); Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) From 8ebf49a35b643d61b36b5394203fe8cf5bf6f6b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 20:54:57 -0800 Subject: [PATCH 264/916] Only lower-case the model name The skeleton name will already be lower-case --- components/nifogre/ogre_nif_loader.cpp | 12 +++++------- components/nifogre/ogre_nif_loader.hpp | 8 +++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index f1aecf720..04b2822e0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1043,11 +1043,8 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshPairMap; static MeshPairMap sMeshPairMap; -MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group) +MeshPairList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) { - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - std::transform(skelName.begin(), skelName.end(), skelName.begin(), ::tolower); - MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName); if(meshiter != sMeshPairMap.end()) return meshiter->second; @@ -1081,10 +1078,11 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::string &name, const std::string &group) +EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); MeshPairList meshes = load(name, name, group); if(meshes.size() == 0) return entitylist; @@ -1124,11 +1122,11 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, const std::str EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, - const std::string &name, - const std::string &group) + std::string name, const std::string &group) { EntityList entitylist; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); if(meshes.size() == 0) return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 9dcd0bea6..47d1573fe 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -70,21 +70,19 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(std::string name, std::string skelName, const std::string &group); + static MeshPairList load(const std::string &name, const std::string &skelName, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, - const std::string &name, + std::string name, const std::string &group="General"); static EntityList createEntities(Ogre::SceneNode *parentNode, - const std::string &name, + std::string name, const std::string &group="General"); }; } #endif - - From efca5ded472f6ea9a0a86f80257d1ab2191a10eb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 5 Jan 2013 21:12:08 -0800 Subject: [PATCH 265/916] Clean up some header includes to reduce nesting --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/creature.cpp | 1 + apps/openmw/mwclass/creature.hpp | 4 +--- apps/openmw/mwrender/actors.cpp | 13 ++++++++++--- apps/openmw/mwrender/actors.hpp | 16 +++++++++------- apps/openmw/mwrender/animation.hpp | 15 ++++----------- apps/openmw/mwrender/characterpreview.cpp | 1 + apps/openmw/mwrender/creatureanimation.hpp | 17 ++++++++++------- apps/openmw/mwrender/npcanimation.hpp | 9 +++++---- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- apps/openmw/mwworld/scene.cpp | 1 + 11 files changed, 45 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cc625b306..0c9110ed4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -6,6 +6,7 @@ #include #include "../mwworld/globals.hpp" +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -42,7 +43,6 @@ namespace MWWorld class CellStore; class Player; class LocalScripts; - class Ptr; class TimeStamp; class ESMStore; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index edf5dd25d..7b0f9f728 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -18,6 +18,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/actors.hpp" #include "../mwgui/tooltips.hpp" diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index a158fa743..a96c18a8c 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,9 +1,7 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "../mwrender/renderinginterface.hpp" -#include "../mwrender/actors.hpp" - +#include "../mwworld/class.hpp" namespace MWClass { diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 05bb030d7..fc5a46d12 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -3,15 +3,20 @@ #include #include +#include "../mwworld/ptr.hpp" + +#include "animation.hpp" +#include "creatureanimation.hpp" +#include "npcanimation.hpp" + #include "renderconst.hpp" +namespace MWRender +{ using namespace Ogre; -using namespace MWRender; -using namespace NifOgre; Actors::~Actors(){ - std::map::iterator it = mAllActors.begin(); for (; it != mAllActors.end(); ++it) { delete it->second; @@ -156,3 +161,5 @@ Actors::updateObjectCell(const MWWorld::Ptr &ptr) mAllActors[ptr] = anim; } } + +} diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 073c5d51f..71be0bd7b 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -1,25 +1,27 @@ #ifndef _GAME_RENDER_ACTORS_H #define _GAME_RENDER_ACTORS_H -#include "npcanimation.hpp" -#include "creatureanimation.hpp" +#include namespace MWWorld { class Ptr; class CellStore; + class InventoryStore; } -namespace MWRender{ - class Actors{ +namespace MWRender +{ + class Animation; + + class Actors + { OEngine::Render::OgreRenderer &mRend; std::map mCellSceneNodes; Ogre::SceneNode* mMwRoot; std::map mAllActors; - - - public: + public: Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); void setMwRoot(Ogre::SceneNode* root); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index de4778d87..633a3f9e7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,20 +1,13 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H -#include - #include -#include -#include "../mwworld/actiontalk.hpp" -#include -#include +namespace MWRender +{ - - -namespace MWRender { - -class Animation { +class Animation +{ struct GroupTimes { float mStart; float mStop; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 0a11dc281..b144466c9 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -10,6 +10,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" #include "renderconst.hpp" #include "npcanimation.hpp" diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index e1a7bbb8f..5456f857f 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -3,18 +3,21 @@ #include "animation.hpp" -#include "components/nifogre/ogre_nif_loader.hpp" +namespace MWWorld +{ + class Ptr; +} - -namespace MWRender{ - - class CreatureAnimation: public Animation +namespace MWRender +{ + class CreatureAnimation : public Animation { public: - virtual ~CreatureAnimation(); CreatureAnimation(const MWWorld::Ptr& ptr); - virtual void runAnimation(float timepassed); + virtual ~CreatureAnimation(); + virtual void runAnimation(float timepassed); }; } + #endif diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ca76dcc22..ff853de71 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -3,9 +3,7 @@ #include "animation.hpp" -#include "components/nifogre/ogre_nif_loader.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwclass/npc.hpp" #include "../mwworld/containerstore.hpp" namespace ESM @@ -13,9 +11,11 @@ namespace ESM struct NPC; } -namespace MWRender{ +namespace MWRender +{ -class NpcAnimation: public Animation{ +class NpcAnimation : public Animation +{ private: MWWorld::InventoryStore& mInv; int mStateID; @@ -91,4 +91,5 @@ public: }; } + #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8cb8e9fa8..71424aaed 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -19,8 +19,9 @@ #include #include -#include "../mwworld/esmstore.hpp" #include +#include "../mwworld/esmstore.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6b9abf508..6a6ad92d7 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -10,6 +10,7 @@ #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" +#include "class.hpp" #include "cellfunctors.hpp" From 99769879e30ce15a2eda7765eea6727f01a50b64 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 00:32:38 -0800 Subject: [PATCH 266/916] Fix some createEntities calls --- apps/openmw/mwrender/sky.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 60ecd4303..c8a6ca0ef 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -324,7 +324,7 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif"); + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { Entity* night1_ent = entities.mEntities[i]; @@ -349,7 +349,7 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, NULL, "meshes\\sky_atmosphere.nif"); + entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* atmosphere_ent = entities.mEntities[i]; @@ -363,7 +363,7 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(clouds_node, NULL, "meshes\\sky_clouds_01.nif"); + entities = NifOgre::NIFLoader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* clouds_ent = entities.mEntities[i]; From 976b042cca0891e3a21b59af2795b4361e38534a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 01:59:18 -0800 Subject: [PATCH 267/916] Use a list to reduce some repeating code --- apps/openmw/mwrender/npcanimation.cpp | 264 ++++++++------------------ apps/openmw/mwrender/npcanimation.hpp | 12 +- 2 files changed, 88 insertions(+), 188 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c76c67425..37c8aee64 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -14,34 +14,46 @@ using namespace Ogre; using namespace NifOgre; -namespace MWRender{ +namespace MWRender +{ + +const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { + { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, + { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, + { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, + { ESM::PRT_Cuirass, &NpcAnimation::mChest, "Chest" }, + { ESM::PRT_Groin, &NpcAnimation::mGroin, "Groin" }, + { ESM::PRT_Skirt, &NpcAnimation::mSkirt, "Groin" }, + { ESM::PRT_RHand, &NpcAnimation::mHandR, "Right Hand" }, + { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, + { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, + { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, + { ESM::PRT_Shield, NULL, "" }, + { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, + { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, + { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, + { ESM::PRT_LUpperarm, &NpcAnimation::mUpperArmL, "Left Upper Arm" }, + { ESM::PRT_RFoot, &NpcAnimation::mFootR, "Right Foot" }, + { ESM::PRT_LFoot, &NpcAnimation::mFootL, "Left Foot" }, + { ESM::PRT_RAnkle, &NpcAnimation::mAnkleR, "Right Ankle" }, + { ESM::PRT_LAnkle, &NpcAnimation::mAnkleL, "Left Ankle" }, + { ESM::PRT_RKnee, &NpcAnimation::mKneeR, "Right Knee" }, + { ESM::PRT_LKnee, &NpcAnimation::mKneeL, "Left Knee" }, + { ESM::PRT_RLeg, &NpcAnimation::mUpperLegR, "Right Upper Leg" }, + { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, + { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, + { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, + { ESM::PRT_Weapon, NULL, "" }, + { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } +}; + NpcAnimation::~NpcAnimation() { - removeEntities(mHead); - removeEntities(mHair); - removeEntities(mNeck); - removeEntities(mChest); - removeEntities(mGroin); - removeEntities(mSkirt); - removeEntities(mHandL); - removeEntities(mHandR); - removeEntities(mWristL); - removeEntities(mWristR); - removeEntities(mForearmL); - removeEntities(mForearmR); - removeEntities(mUpperArmL); - removeEntities(mUpperArmR); - removeEntities(mFootL); - removeEntities(mFootR); - removeEntities(mAnkleL); - removeEntities(mAnkleR); - removeEntities(mKneeL); - removeEntities(mKneeR); - removeEntities(mUpperLegL); - removeEntities(mUpperLegR); - removeEntities(mClavicleL); - removeEntities(mClavicleR); - removeEntities(mTail); + for(size_t i = 0;i < sPartListSize;i++) + { + if(sPartList[i].ents) + removeEntities(this->*sPartList[i].ents); + } } @@ -90,9 +102,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor { Ogre::Entity *base = mEntityList.mEntities[i]; - base->getUserObjectBindings ().setUserAny (Ogre::Any(-1)); - + base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); base->setVisibilityFlags(mVisibilityFlags); + bool transparent = false; for(unsigned int j=0;j < base->getNumSubEntities();++j) { @@ -126,29 +138,29 @@ void NpcAnimation::updateParts() { bool apparelChanged = false; - const struct { - MWWorld::ContainerStoreIterator *iter; + static const struct { + MWWorld::ContainerStoreIterator NpcAnimation::*iter; int slot; } slotlist[] = { - { &mRobe, MWWorld::InventoryStore::Slot_Robe }, - { &mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, - { &mHelmet, MWWorld::InventoryStore::Slot_Helmet }, - { &mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, - { &mGreaves, MWWorld::InventoryStore::Slot_Greaves }, - { &mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, - { &mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, - { &mBoots, MWWorld::InventoryStore::Slot_Boots }, - { &mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, - { &mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, - { &mShirt, MWWorld::InventoryStore::Slot_Shirt }, - { &mPants, MWWorld::InventoryStore::Slot_Pants }, + { &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe }, + { &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, + { &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet }, + { &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, + { &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves }, + { &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, + { &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, + { &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots }, + { &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, + { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt }, + { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants }, }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(*slotlist[i].iter != iter) + if(this->*slotlist[i].iter != iter) { - *slotlist[i].iter = iter; + this->*slotlist[i].iter = iter; removePartGroup(slotlist[i].slot); apparelChanged = true; } @@ -318,21 +330,18 @@ void NpcAnimation::updateParts() if(mPartPriorities[PartTypeList[i].type] < 1) { const ESM::BodyPart *part = NULL; - const MWWorld::Store &partStore = - store.get(); + const MWWorld::Store &partStore = store.get(); - if (!mNpc->isMale()) { + if(!mNpc->isMale()) + { part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); - } } - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); - } - if (part == 0) { + if(part == 0) part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); - } if(part) addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); @@ -348,7 +357,7 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int for(size_t i = 0;i < parts.size();i++) { parts[i]->setVisibilityFlags(mVisibilityFlags); - parts[i]->getUserObjectBindings ().setUserAny (Ogre::Any(group)); + parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); } return entities; } @@ -384,62 +393,15 @@ void NpcAnimation::removeIndividualPart(int type) mPartPriorities[type] = 0; mPartslots[type] = -1; - if(type == ESM::PRT_Head) //0 - removeEntities(mHead); - else if(type == ESM::PRT_Hair) //1 - removeEntities(mHair); - else if(type == ESM::PRT_Neck) //2 - removeEntities(mNeck); - else if(type == ESM::PRT_Cuirass)//3 - removeEntities(mChest); - else if(type == ESM::PRT_Groin)//4 - removeEntities(mGroin); - else if(type == ESM::PRT_Skirt)//5 - removeEntities(mSkirt); - else if(type == ESM::PRT_RHand)//6 - removeEntities(mHandR); - else if(type == ESM::PRT_LHand)//7 - removeEntities(mHandL); - else if(type == ESM::PRT_RWrist)//8 - removeEntities(mWristR); - else if(type == ESM::PRT_LWrist) //9 - removeEntities(mWristL); - else if(type == ESM::PRT_Shield) //10 + for(size_t i = 0;i < sPartListSize;i++) { + if(type == sPartList[i].type) + { + if(sPartList[i].ents) + removeEntities(this->*sPartList[i].ents); + break; + } } - else if(type == ESM::PRT_RForearm) //11 - removeEntities(mForearmR); - else if(type == ESM::PRT_LForearm) //12 - removeEntities(mForearmL); - else if(type == ESM::PRT_RUpperarm) //13 - removeEntities(mUpperArmR); - else if(type == ESM::PRT_LUpperarm) //14 - removeEntities(mUpperArmL); - else if(type == ESM::PRT_RFoot) //15 - removeEntities(mFootR); - else if(type == ESM::PRT_LFoot) //16 - removeEntities(mFootL); - else if(type == ESM::PRT_RAnkle) //17 - removeEntities(mAnkleR); - else if(type == ESM::PRT_LAnkle) //18 - removeEntities(mAnkleL); - else if(type == ESM::PRT_RKnee) //19 - removeEntities(mKneeR); - else if(type == ESM::PRT_LKnee) //20 - removeEntities(mKneeL); - else if(type == ESM::PRT_RLeg) //21 - removeEntities(mUpperLegR); - else if(type == ESM::PRT_LLeg) //22 - removeEntities(mUpperLegL); - else if(type == ESM::PRT_RPauldron) //23 - removeEntities(mClavicleR); - else if(type == ESM::PRT_LPauldron) //24 - removeEntities(mClavicleL); - else if(type == ESM::PRT_Weapon) //25 - { - } - else if(type == ESM::PRT_Tail) //26 - removeEntities(mTail); } void NpcAnimation::reserveIndividualPart(int type, int group, int priority) @@ -469,87 +431,15 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, removeIndividualPart(type); mPartslots[type] = group; mPartPriorities[type] = priority; - switch(type) + + for(size_t i = 0;i < sPartListSize;i++) { - case ESM::PRT_Head: //0 - mHead = insertBoundedPart(mesh, group, "Head"); - break; - case ESM::PRT_Hair: //1 - mHair = insertBoundedPart(mesh, group, "Head"); - break; - case ESM::PRT_Neck: //2 - mNeck = insertBoundedPart(mesh, group, "Neck"); - break; - case ESM::PRT_Cuirass: //3 - mChest = insertBoundedPart(mesh, group, "Chest"); - break; - case ESM::PRT_Groin: //4 - mGroin = insertBoundedPart(mesh, group, "Groin"); - break; - case ESM::PRT_Skirt: //5 - mSkirt = insertBoundedPart(mesh, group, "Groin"); - break; - case ESM::PRT_RHand: //6 - mHandR = insertBoundedPart(mesh, group, "Right Hand"); - break; - case ESM::PRT_LHand: //7 - mHandL = insertBoundedPart(mesh, group, "Left Hand"); - break; - case ESM::PRT_RWrist: //8 - mWristR = insertBoundedPart(mesh, group, "Right Wrist"); - break; - case ESM::PRT_LWrist: //9 - mWristL = insertBoundedPart(mesh, group, "Left Wrist"); - break; - case ESM::PRT_Shield: //10 - break; - case ESM::PRT_RForearm: //11 - mForearmR = insertBoundedPart(mesh, group, "Right Forearm"); - break; - case ESM::PRT_LForearm: //12 - mForearmL = insertBoundedPart(mesh, group, "Left Forearm"); - break; - case ESM::PRT_RUpperarm: //13 - mUpperArmR = insertBoundedPart(mesh, group, "Right Upper Arm"); - break; - case ESM::PRT_LUpperarm: //14 - mUpperArmL = insertBoundedPart(mesh, group, "Left Upper Arm"); - break; - case ESM::PRT_RFoot: //15 - mFootR = insertBoundedPart(mesh, group, "Right Foot"); - break; - case ESM::PRT_LFoot: //16 - mFootL = insertBoundedPart(mesh, group, "Left Foot"); - break; - case ESM::PRT_RAnkle: //17 - mAnkleR = insertBoundedPart(mesh, group, "Right Ankle"); - break; - case ESM::PRT_LAnkle: //18 - mAnkleL = insertBoundedPart(mesh, group, "Left Ankle"); - break; - case ESM::PRT_RKnee: //19 - mKneeR = insertBoundedPart(mesh, group, "Right Knee"); - break; - case ESM::PRT_LKnee: //20 - mKneeL = insertBoundedPart(mesh, group, "Left Knee"); - break; - case ESM::PRT_RLeg: //21 - mUpperLegR = insertBoundedPart(mesh, group, "Right Upper Leg"); - break; - case ESM::PRT_LLeg: //22 - mUpperLegL = insertBoundedPart(mesh, group, "Left Upper Leg"); - break; - case ESM::PRT_RPauldron: //23 - mClavicleR = insertBoundedPart(mesh , group, "Right Clavicle"); - break; - case ESM::PRT_LPauldron: //24 - mClavicleL = insertBoundedPart(mesh, group, "Left Clavicle"); - break; - case ESM::PRT_Weapon: //25 - break; - case ESM::PRT_Tail: //26 - mTail = insertBoundedPart(mesh, group, "Tail"); + if(type == sPartList[i].type) + { + if(sPartList[i].ents) + this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); break; + } } return true; } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ff853de71..e6eee5491 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -14,6 +14,14 @@ namespace ESM namespace MWRender { +class NpcAnimation; + +struct PartInfo { + ESM::PartReferenceType type; + NifOgre::EntityList NpcAnimation::*ents; + const char name[32]; +}; + class NpcAnimation : public Animation { private: @@ -55,7 +63,6 @@ private: std::string mHairModel; std::string mBodyPrefix; - float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; MWWorld::ContainerStoreIterator mHelmet; @@ -72,6 +79,9 @@ private: int mVisibilityFlags; + static const size_t sPartListSize = 27; + static const PartInfo sPartList[sPartListSize]; + public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags); From 0b7d11d38d99033a09bed6b22c75378f692653a5 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 6 Jan 2013 11:39:18 +0100 Subject: [PATCH 268/916] to_utf8 test: fix Utf8Encoder constructor --- components/to_utf8/tests/to_utf8_test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/to_utf8/tests/to_utf8_test.cpp b/components/to_utf8/tests/to_utf8_test.cpp index 4bba0cf90..3fcddd158 100644 --- a/components/to_utf8/tests/to_utf8_test.cpp +++ b/components/to_utf8/tests/to_utf8_test.cpp @@ -18,8 +18,7 @@ void testEncoder(ToUTF8::FromType encoding, const std::string &legacyEncFile, std::string utf8Line = getFirstLine(utf8File); // create an encoder for specified character encoding - ToUTF8::Utf8Encoder encoder; - encoder.setEncoding(encoding); + ToUTF8::Utf8Encoder encoder (encoding); // convert text to UTF-8 std::string convertedUtf8Line = encoder.getUtf8(legacyEncLine); From 2b1fe7dc44652f1531fb9aa70c67a62cb19e6752 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 05:39:39 -0800 Subject: [PATCH 269/916] Add part info for weapons and shields --- apps/openmw/mwrender/npcanimation.cpp | 25 ++++++++++--------------- apps/openmw/mwrender/npcanimation.hpp | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 37c8aee64..b7e93cef2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -17,7 +17,7 @@ using namespace NifOgre; namespace MWRender { -const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { +const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, @@ -28,7 +28,7 @@ const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, - { ESM::PRT_Shield, NULL, "" }, + { ESM::PRT_Shield, &NpcAnimation::mShield, "Shield" }, { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, @@ -43,24 +43,21 @@ const PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, - { ESM::PRT_Weapon, NULL, "" }, + { ESM::PRT_Weapon, &NpcAnimation::mWeapon, "Weapon" }, { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } }; NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - { - if(sPartList[i].ents) - removeEntities(this->*sPartList[i].ents); - } + removeEntities(this->*sPartList[i].ents); } NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(), - mStateID(-1), mInv(inv), + mStateID(-1), mTimeToChange(0), mVisibilityFlags(visibilityFlags), mRobe(mInv.end()), @@ -78,10 +75,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor { mNpc = ptr.get()->mBase; - for (int init = 0; init < 27; init++) + for(size_t i = 0;i < sPartListSize;i++) { - mPartslots[init] = -1; //each slot is empty - mPartPriorities[init] = 0; + mPartslots[i] = -1; //each slot is empty + mPartPriorities[i] = 0; } const MWWorld::ESMStore &store = @@ -397,8 +394,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - if(sPartList[i].ents) - removeEntities(this->*sPartList[i].ents); + removeEntities(this->*sPartList[i].ents); break; } } @@ -436,8 +432,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - if(sPartList[i].ents) - this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); + this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index e6eee5491..090366a23 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -14,23 +14,22 @@ namespace ESM namespace MWRender { -class NpcAnimation; - +class NpcAnimation : public Animation +{ +public: struct PartInfo { ESM::PartReferenceType type; NifOgre::EntityList NpcAnimation::*ents; const char name[32]; }; -class NpcAnimation : public Animation -{ private: + static const size_t sPartListSize = 27; + static const PartInfo sPartList[sPartListSize]; + MWWorld::InventoryStore& mInv; int mStateID; - int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty - int mPartPriorities[27]; - //Bounded Parts NifOgre::EntityList mClavicleL; NifOgre::EntityList mClavicleR; @@ -54,6 +53,8 @@ private: NifOgre::EntityList mHair; NifOgre::EntityList mHandL; NifOgre::EntityList mHandR; + NifOgre::EntityList mShield; + NifOgre::EntityList mWeapon; NifOgre::EntityList mHead; NifOgre::EntityList mChest; NifOgre::EntityList mTail; @@ -79,8 +80,8 @@ private: int mVisibilityFlags; - static const size_t sPartListSize = 27; - static const PartInfo sPartList[sPartListSize]; + int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty + int mPartPriorities[sPartListSize]; public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, From 1d3f3bcce30b211ba92b03fee3b7814042f0048c Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sun, 6 Jan 2013 19:19:12 +0400 Subject: [PATCH 270/916] clang build fix --- components/files/constrainedfiledatastream.cpp | 4 ++++ components/translation/translation.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp index 63bd3490f..dd2985e56 100644 --- a/components/files/constrainedfiledatastream.cpp +++ b/components/files/constrainedfiledatastream.cpp @@ -3,7 +3,11 @@ #include #include +#ifndef __clang__ #include +#else +#include +#endif namespace { diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index fb5b03861..37bceafbf 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -30,7 +30,7 @@ namespace Translation { std::string path = dataFileCollections.getCollection (extension).getPath (fileName).string(); - std::ifstream stream (path); + std::ifstream stream (path.c_str()); if (!stream.is_open()) throw std::runtime_error ("failed to open translation file: " + fileName); From 0f3712f28435fdf2133d0c5c8eb22814349aed55 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 6 Jan 2013 10:45:54 -0800 Subject: [PATCH 271/916] change flickering light's brightness pattern --- apps/openmw/mwrender/objects.cpp | 134 +++++++++++++++++++------------ apps/openmw/mwrender/objects.hpp | 13 ++- 2 files changed, 87 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 36f09e6d9..825ce2a14 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -235,8 +235,9 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f else info.type = LT_Normal; - // random starting phase for the animation - info.time = Ogre::Math::RangeRandom(0, 2 * Ogre::Math::PI); + // randomize lights animations + info.time = Ogre::Math::RangeRandom(-500, +500); + info.phase = Ogre::Math::RangeRandom(-500, +500); // adjust the lights depending if we're in an interior or exterior cell // quadratic means the light intensity falls off quite fast, resulting in a @@ -373,6 +374,48 @@ void Objects::disableLights() } } +namespace pulse +{ + static float frequency (float x) + { + return x; + } + + static float amplitude (float phase) + { + return sin (phase); + } +} + +namespace flicker +{ + static const float fa = 0.785398f; + static const float fb = 1.17024f; + + static const float tdo = 0.94f; + static const float tdm = 2.48f; + + static const float f [3] = { 1.5708f, 4.18774f, 5.19934f }; + static const float o [3] = { 0.804248f, 2.11115f, 3.46832f }; + static const float m [3] = { 1.0f, 0.785f, 0.876f }; + static const float s = 0.394f; + + static const float phase_wavelength = 120.0f * 3.14159265359f / fa; + + static float frequency (float x) + { + return tdo + tdm * sin (fa * x); + } + + static float amplitude (float x) + { + float v = 0.0f; + for (int i = 0; i < 3; ++i) + v += sin (fb*x*f[i] + o[1])*m[i]; + return v * s; + } +} + void Objects::update(const float dt) { std::vector::iterator it = mLights.begin(); @@ -382,77 +425,64 @@ void Objects::update(const float dt) { Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); - // Light animation (pulse & flicker) - it->time += dt; - const float phase = std::fmod(static_cast (it->time), static_cast(32 * 2 * Ogre::Math::PI)) * 20; - float pulseConstant; + + float brightness; + float cycle_time; + float time_distortion; + + if ((it->type == LT_Pulse) && (it->type == LT_PulseSlow)) + { + cycle_time = 2 * Ogre::Math::PI; + time_distortion = 20.0f; + } + else + { + cycle_time = 500.0f; + it->phase = fmod (it->phase + dt, flicker::phase_wavelength); + time_distortion = flicker::frequency (it->phase); + } + + it->time += it->dir*dt*time_distortion; + if (it->dir > 0 && it->time > +cycle_time) + { + it->dir = -1.0f; + it->time = +2*cycle_time - it->time; + } + if (it->dir < 0 && it->time < -cycle_time) + { + it->dir = +1.0f; + it->time = -2*cycle_time - it->time; + } + + static const float fast = 4.0f/1.0f; + static const float slow = 1.0f/1.0f; // These formulas are just guesswork, but they work pretty well if (it->type == LT_Normal) { // Less than 1/255 light modifier for a constant light: - pulseConstant = (const float)(1.0 + sin(phase) / 255.0 ); + brightness = (const float)(1.0 + flicker::amplitude(it->time*slow) / 255.0 ); } else if (it->type == LT_Flicker) { - // Let's do a 50% -> 100% sine wave pulse over 1 second: - // This is 75% +/- 25% - pulseConstant = (const float)(0.75 + sin(phase) * 0.25); - - // Then add a 25% flicker variation: - it->resetTime -= dt; - if (it->resetTime < 0) - { - it->flickerVariation = (rand() % 1000) / 1000 * 0.25; - it->resetTime = 0.5; - } - if (it->resetTime > 0.25) - { - pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime * 2.0f) + pulseConstant * it->resetTime * 2.0f; - } - else - { - pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime * 2.0f) + pulseConstant * (1-it->resetTime * 2.0f); - } + brightness = (const float)(0.75 + flicker::amplitude(it->time*fast) * 0.25); } else if (it->type == LT_FlickerSlow) { - // Let's do a 50% -> 100% sine wave pulse over 1 second: - // This is 75% +/- 25% - pulseConstant = (const float)(0.75 + sin(phase / 4.0) * 0.25); - - // Then add a 25% flicker variation: - it->resetTime -= dt; - if (it->resetTime < 0) - { - it->flickerVariation = (rand() % 1000) / 1000 * 0.25; - it->resetTime = 0.5; - } - if (it->resetTime > 0.5) - { - pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime) + pulseConstant * it->resetTime; - } - else - { - pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime) + pulseConstant * (1-it->resetTime); - } + brightness = (const float)(0.75 + flicker::amplitude(it->time*slow) * 0.25); } else if (it->type == LT_Pulse) { - // Let's do a 75% -> 125% sine wave pulse over 1 second: - // This is 100% +/- 25% - pulseConstant = (const float)(1.0 + sin(phase) * 0.25); + brightness = (const float)(1.0 + pulse::amplitude (it->time*fast) * 0.25); } else if (it->type == LT_PulseSlow) { - // Let's do a 75% -> 125% sine wave pulse over 1 second: - // This is 100% +/- 25% - pulseConstant = (const float)(1.0 + sin(phase / 4.0) * 0.25); + brightness = (const float)(1.0 + pulse::amplitude (it->time*slow) * 0.25); } else assert(0 && "Invalid light type"); - light->setDiffuseColour( it->colour * pulseConstant ); + light->setDiffuseColour(it->colour * brightness); ++it; } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 8594e4fe4..48632dba8 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -34,16 +34,13 @@ struct LightInfo LightType type; // Runtime variables - float flickerVariation; // 25% flicker variation, reset once every 0.5 seconds - float flickerSlowVariation; // 25% flicker variation, reset once every 1.0 seconds - float resetTime; - long double time; - + float dir; // direction time is running... + float time; // current time + float phase; // current phase LightInfo() : - flickerVariation(0), resetTime(0.5), - flickerSlowVariation(0), time(0), interior(true), - type(LT_Normal), radius(1.0) + dir(1.0f), time(0.0f), phase (0.0f), + interior(true), type(LT_Normal), radius(1.0) { } }; From b96a9797199d4fa076d6516d59e9a892d744e8c2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 17:05:48 -0800 Subject: [PATCH 272/916] Store an MWWorld::Ptr with the Animation --- apps/openmw/mwrender/animation.cpp | 5 +++-- apps/openmw/mwrender/animation.hpp | 5 ++++- apps/openmw/mwrender/creatureanimation.cpp | 7 ++++--- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d2d253b91..d7f3d52d6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -10,8 +10,9 @@ namespace MWRender { -Animation::Animation() - : mInsert(NULL) +Animation::Animation(const MWWorld::Ptr &ptr) + : mPtr(ptr) + , mInsert(NULL) , mTime(0.0f) , mSkipFrame(false) , mAnimState(NULL) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 633a3f9e7..593538ea6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -3,6 +3,8 @@ #include +#include "../mwworld/ptr.hpp" + namespace MWRender { @@ -23,6 +25,7 @@ class Animation }; protected: + MWWorld::Ptr mPtr; Ogre::SceneNode* mInsert; float mTime; @@ -40,7 +43,7 @@ protected: void createEntityList(Ogre::SceneNode *node, const std::string &model); public: - Animation(); + Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); void playGroup(std::string groupname, int mode, int loops); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 1ca897c15..caa040d95 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -16,16 +16,17 @@ CreatureAnimation::~CreatureAnimation() { } -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr): Animation() +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) + : Animation(ptr) { - MWWorld::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = mPtr.get(); assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { std::string mesh = "meshes\\" + ref->mBase->mModel; - createEntityList(ptr.getRefData().getBaseNode(), mesh); + createEntityList(mPtr.getRefData().getBaseNode(), mesh); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b7e93cef2..5682a86cc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -55,7 +55,7 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) - : Animation(), + : Animation(ptr), mInv(inv), mStateID(-1), mTimeToChange(0), @@ -73,7 +73,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mGloveR(mInv.end()), mSkirtIter(mInv.end()) { - mNpc = ptr.get()->mBase; + mNpc = mPtr.get()->mBase; for(size_t i = 0;i < sPartListSize;i++) { From 910619eb21c05fc9baa93e139a7d011bce9ea775 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 17:31:53 -0800 Subject: [PATCH 273/916] Store the NonAccum animation root from the skeleton instance Currently this is assumed to be the node with the animation text keys. --- apps/openmw/mwrender/animation.cpp | 4 +++- apps/openmw/mwrender/animation.hpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d7f3d52d6..b8be879e5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -14,8 +14,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mInsert(NULL) , mTime(0.0f) - , mSkipFrame(false) , mAnimState(NULL) + , mSkipFrame(false) + , mNonAccumRoot(NULL) { } @@ -62,6 +63,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); + mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getHandle()); break; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 593538ea6..3bc173d70 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,12 +31,13 @@ protected: float mTime; GroupTimes mCurGroup; GroupTimes mNextGroup; + Ogre::AnimationState *mAnimState; bool mSkipFrame; NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; - Ogre::AnimationState *mAnimState; + Ogre::Node *mNonAccumRoot; bool findGroupTimes(const std::string &groupname, GroupTimes *times); From 7ba09ff025e07250a88261a1b099f377717a72a2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 20:05:50 -0800 Subject: [PATCH 274/916] Catch errors from buildBones --- components/nifogre/ogre_nif_loader.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 04b2822e0..3c8b3067a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -367,7 +367,14 @@ void loadResource(Ogre::Resource *resource) const Nif::Node *node = dynamic_cast(nif.getRecord(0)); std::vector ctrls; - buildBones(skel, node, ctrls); + try { + buildBones(skel, node, ctrls); + } + catch(std::exception &e) { + std::cerr<< "Exception while loading "<getName() < targets; // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file From 5b3a20ef69c23eea4f65b138aca43517c497963c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 21:18:48 -0800 Subject: [PATCH 275/916] Update the object position as the animation moves --- apps/openmw/mwrender/animation.cpp | 76 ++++++++++++++++++++--- apps/openmw/mwrender/animation.hpp | 11 +++- apps/openmw/mwrender/characterpreview.cpp | 1 - 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b8be879e5..b73d35264 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -7,6 +7,9 @@ #include #include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + namespace MWRender { @@ -16,8 +19,14 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mTime(0.0f) , mAnimState(NULL) , mSkipFrame(false) + , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mLastPosition(0.0f) { + mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; + mCurGroup.mLoopStop = mCurGroup.mStop = 0.0f; + mNextGroup.mStart = mNextGroup.mLoopStart = 0.0f; + mNextGroup.mLoopStop = mNextGroup.mStop = 0.0f; } Animation::~Animation() @@ -52,9 +61,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAnimState = state; } + Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(mEntityList.mSkelBase->getSkeleton()->getName()); + Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); while(iter.hasMoreElements()) { @@ -63,7 +73,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); - mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getHandle()); + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); + mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mLastPosition = mNonAccumRoot->getPosition(); break; } } @@ -71,6 +84,43 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +void Animation::updatePosition(float time) +{ + mAnimState->setTimePosition(time); + if(mNonAccumRoot) + { + /* Update the animation and get the non-accumulation root's difference from the + * last update. */ + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; + + /* Translate the accumulation root back to compensate for the move. */ + mAccumRoot->translate(-posdiff); + mLastPosition += posdiff; + + /* Finally, move the object based on how much the non-accumulation root moved. */ + Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); + newpos += mInsert->getOrientation() * posdiff; + + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + } +} + +void Animation::resetPosition(float time) +{ + mAnimState->setTimePosition(time); + if(mNonAccumRoot) + { + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mLastPosition = mNonAccumRoot->getPosition(); + /* FIXME: This should be set to -mLastPosition, but without proper collision the + * model gets placed halfway into the ground. */ + mAccumRoot->setPosition(0.0f, 0.0f, 0.0f); + } +} + + struct checklow { bool operator()(const char &a, const char &b) const { @@ -145,6 +195,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup = times; mNextGroup = GroupTimes(); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); + resetPosition(mTime); } } @@ -155,29 +206,36 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mCurGroup.mLoops > 0 && !mSkipFrame) + if(mAnimState && !mSkipFrame) { mTime += timepassed; + recheck: if(mTime >= mCurGroup.mLoopStop) { if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; + updatePosition(mCurGroup.mLoopStop); mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart; + resetPosition(mCurGroup.mLoopStart); + goto recheck; } else if(mTime >= mCurGroup.mStop) { if(mNextGroup.mLoops > 0) + { + updatePosition(mCurGroup.mStop); mTime = mTime - mCurGroup.mStop + mNextGroup.mStart; - else - mTime = mCurGroup.mStop; - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); + resetPosition(mNextGroup.mStart); + mCurGroup = mNextGroup; + mNextGroup = GroupTimes(); + goto recheck; + } + mTime = mCurGroup.mStop; } } - if(mAnimState) - mAnimState->setTimePosition(mTime); + updatePosition(mTime); } mSkipFrame = false; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3bc173d70..d1ae5af4c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -37,7 +37,16 @@ protected: NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; - Ogre::Node *mNonAccumRoot; + Ogre::Bone *mAccumRoot; + Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mLastPosition; + + /* Updates the animation to the specified time, and moves the mPtr object + * based on the change since the last update or reset. */ + void updatePosition(float time); + /* Updates the animation to the specified time, without moving the mPtr + * object. */ + void resetPosition(float time); bool findGroupTimes(const std::string &groupname, GroupTimes *times); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b144466c9..7431c2a61 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -138,7 +138,6 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->playGroup ("inventoryhandtohand", 0, 1); - mAnimation->runAnimation (0); } // -------------------------------------------------------------------------------------------------- From 648e3331f51e5ee75176b82f72d3860e635548ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 6 Jan 2013 23:20:20 -0800 Subject: [PATCH 276/916] Don't try to move objects that aren't in a cell --- apps/openmw/mwrender/animation.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b73d35264..4cf0db3ed 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,12 +98,15 @@ void Animation::updatePosition(float time) mAccumRoot->translate(-posdiff); mLastPosition += posdiff; - /* Finally, move the object based on how much the non-accumulation root moved. */ - Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); - newpos += mInsert->getOrientation() * posdiff; + if(mPtr.isInCell()) + { + /* Finally, move the object based on how much the non-accumulation root moved. */ + Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); + newpos += mInsert->getOrientation() * posdiff; - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); + } } } From 2557ef4d7d43e950b7f5db74ccde91fef35fa668 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 7 Jan 2013 12:17:46 +0100 Subject: [PATCH 277/916] post merge fixes and some misc clean up --- apps/openmw/mwrender/objects.cpp | 77 +++++++++++++++----------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 825ce2a14..ee36126f8 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -17,7 +17,7 @@ using namespace MWRender; -// These are the Morrowind.ini defaults +/// \todo Replace these, once fallback values from the ini file are available. float Objects::lightLinearValue = 3; float Objects::lightLinearRadiusMult = 1; @@ -31,7 +31,6 @@ int Objects::uniqueID = 0; void Objects::clearSceneNode (Ogre::SceneNode *node) { - /// \todo This should probably be moved into OpenEngine at some point. for (int i=node->numAttachedObjects()-1; i>=0; --i) { Ogre::MovableObject *object = node->getAttachedObject (i); @@ -374,45 +373,43 @@ void Objects::disableLights() } } -namespace pulse +namespace MWRender { - static float frequency (float x) + namespace Pulse { - return x; + static float amplitude (float phase) + { + return sin (phase); + } } - static float amplitude (float phase) + namespace Flicker { - return sin (phase); - } -} + static const float fa = 0.785398f; + static const float fb = 1.17024f; -namespace flicker -{ - static const float fa = 0.785398f; - static const float fb = 1.17024f; + static const float tdo = 0.94f; + static const float tdm = 2.48f; - static const float tdo = 0.94f; - static const float tdm = 2.48f; + static const float f [3] = { 1.5708f, 4.18774f, 5.19934f }; + static const float o [3] = { 0.804248f, 2.11115f, 3.46832f }; + static const float m [3] = { 1.0f, 0.785f, 0.876f }; + static const float s = 0.394f; - static const float f [3] = { 1.5708f, 4.18774f, 5.19934f }; - static const float o [3] = { 0.804248f, 2.11115f, 3.46832f }; - static const float m [3] = { 1.0f, 0.785f, 0.876f }; - static const float s = 0.394f; + static const float phase_wavelength = 120.0f * 3.14159265359f / fa; - static const float phase_wavelength = 120.0f * 3.14159265359f / fa; + static float frequency (float x) + { + return tdo + tdm * sin (fa * x); + } - static float frequency (float x) - { - return tdo + tdm * sin (fa * x); - } - - static float amplitude (float x) - { - float v = 0.0f; - for (int i = 0; i < 3; ++i) - v += sin (fb*x*f[i] + o[1])*m[i]; - return v * s; + static float amplitude (float x) + { + float v = 0.0f; + for (int i = 0; i < 3; ++i) + v += sin (fb*x*f[i] + o[1])*m[i]; + return v * s; + } } } @@ -425,7 +422,6 @@ void Objects::update(const float dt) { Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); - float brightness; float cycle_time; float time_distortion; @@ -438,8 +434,8 @@ void Objects::update(const float dt) else { cycle_time = 500.0f; - it->phase = fmod (it->phase + dt, flicker::phase_wavelength); - time_distortion = flicker::frequency (it->phase); + it->phase = fmod (it->phase + dt, Flicker::phase_wavelength); + time_distortion = Flicker::frequency (it->phase); } it->time += it->dir*dt*time_distortion; @@ -461,23 +457,23 @@ void Objects::update(const float dt) if (it->type == LT_Normal) { // Less than 1/255 light modifier for a constant light: - brightness = (const float)(1.0 + flicker::amplitude(it->time*slow) / 255.0 ); + brightness = (const float)(1.0 + Flicker::amplitude(it->time*slow) / 255.0 ); } else if (it->type == LT_Flicker) { - brightness = (const float)(0.75 + flicker::amplitude(it->time*fast) * 0.25); + brightness = (const float)(0.75 + Flicker::amplitude(it->time*fast) * 0.25); } else if (it->type == LT_FlickerSlow) { - brightness = (const float)(0.75 + flicker::amplitude(it->time*slow) * 0.25); + brightness = (const float)(0.75 + Flicker::amplitude(it->time*slow) * 0.25); } else if (it->type == LT_Pulse) { - brightness = (const float)(1.0 + pulse::amplitude (it->time*fast) * 0.25); + brightness = (const float)(1.0 + Pulse::amplitude (it->time*fast) * 0.25); } else if (it->type == LT_PulseSlow) { - brightness = (const float)(1.0 + pulse::amplitude (it->time*slow) * 0.25); + brightness = (const float)(1.0 + Pulse::amplitude (it->time*slow) * 0.25); } else assert(0 && "Invalid light type"); @@ -506,8 +502,7 @@ void Objects::rebuildStaticGeometry() } } -void -Objects::updateObjectCell(const MWWorld::Ptr &ptr) +void Objects::updateObjectCell(const MWWorld::Ptr &ptr) { Ogre::SceneNode *node; MWWorld::CellStore *newCell = ptr.getCell(); From 35f4d09288aa703cae11a4c04e8a039f978fc378 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Jan 2013 13:06:16 +0100 Subject: [PATCH 278/916] swscale handled better (cmake) --- CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 5 ----- cmake/FindFFmpeg.cmake | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 182cc268a..148f65bdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,7 +146,7 @@ if (USE_FFMPEG) find_package(FFmpeg) if (FFMPEG_FOUND) set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS}) - set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES}) + set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES}) set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG) set(GOT_SOUND_INPUT 1) endif (FFMPEG_FOUND) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 57e81e5ee..4f290c46f 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -110,11 +110,6 @@ target_link_libraries(openmw components ) -if (USE_FFMPEG) - target_link_libraries(openmw - "swscale") -endif() - # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index 526be5f1b..c80203a25 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -32,7 +32,7 @@ include(FindPackageHandleStandardArgs) # The default components were taken from a survey over other FindFFMPEG.cmake files if (NOT FFmpeg_FIND_COMPONENTS) - set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL) + set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) endif () # From 282601d6e9d2ccdbf82ab793218ac210bc270489 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 7 Jan 2013 13:19:52 +0100 Subject: [PATCH 279/916] support the allowSkipping extra parameter for playBink command. --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 6 +++--- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/videoplayer.cpp | 11 ++++++++++- apps/openmw/mwrender/videoplayer.hpp | 5 ++++- apps/openmw/mwscript/miscextensions.cpp | 7 +++++-- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 2 +- 8 files changed, 27 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 198a20d45..7ec25f1ea 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -305,7 +305,7 @@ namespace MWBase /// \todo this does not belong here - virtual void playVideo(const std::string& name) = 0; + virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void stopVideo() = 0; }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3abf88cca..ae7d6612b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -929,14 +929,14 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend rendering.setup (mRendering.getScene()); } -void RenderingManager::playVideo(const std::string& name) +void RenderingManager::playVideo(const std::string& name, bool allowSkipping) { - mVideoPlayer->playVideo ("video/" + name); + mVideoPlayer->playVideo ("video/" + name, allowSkipping); } void RenderingManager::stopVideo() { - mVideoPlayer->close (); + mVideoPlayer->stopVideo (); } } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 02b4bcef6..68f2d79c3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -196,7 +196,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setupExternalRendering (MWRender::ExternalRendering& rendering); - void playVideo(const std::string& name); + void playVideo(const std::string& name, bool allowSkipping); void stopVideo(); protected: diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 8e05a4f82..618331c12 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -1010,6 +1010,7 @@ VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) , mVideoMaterial(NULL) , mRectangle(NULL) , mNode(NULL) + , mAllowSkipping(false) { mVideoMaterial = Ogre::MaterialManager::getSingleton().getByName("VideoMaterial", "General"); if (mVideoMaterial.isNull ()) @@ -1071,8 +1072,10 @@ VideoPlayer::~VideoPlayer() delete mBackgroundRectangle; } -void VideoPlayer::playVideo(const std::string &resourceName) +void VideoPlayer::playVideo(const std::string &resourceName, bool allowSkipping) { + mAllowSkipping = allowSkipping; + if(mState) close(); @@ -1113,6 +1116,12 @@ void VideoPlayer::update () } } +void VideoPlayer::stopVideo () +{ + if (mAllowSkipping) + close(); +} + void VideoPlayer::close() { if(mState) diff --git a/apps/openmw/mwrender/videoplayer.hpp b/apps/openmw/mwrender/videoplayer.hpp index d8c1902aa..5e9d18ba4 100644 --- a/apps/openmw/mwrender/videoplayer.hpp +++ b/apps/openmw/mwrender/videoplayer.hpp @@ -20,11 +20,12 @@ namespace MWRender VideoPlayer(Ogre::SceneManager* sceneMgr); ~VideoPlayer(); - void playVideo (const std::string& resourceName); + void playVideo (const std::string& resourceName, bool allowSkipping); void update(); void close(); + void stopVideo(); bool isPlaying(); @@ -34,6 +35,8 @@ namespace MWRender private: VideoState* mState; + bool mAllowSkipping; + Ogre::SceneManager* mSceneMgr; Ogre::MaterialPtr mVideoMaterial; Ogre::Rectangle2D* mRectangle; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index ef9976a0b..80725b1f2 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -34,7 +34,10 @@ namespace MWScript std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWBase::Environment::get().getWorld ()->playVideo (name); + bool allowSkipping = runtime[0].mInteger; + runtime.pop(); + + MWBase::Environment::get().getWorld ()->playVideo (name, allowSkipping); } }; @@ -465,7 +468,7 @@ namespace MWScript extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode); extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep); extensions.registerInstruction ("wakeuppc", "", opcodeWakeUpPc); - extensions.registerInstruction ("playbink", "S", opcodePlayBink); + extensions.registerInstruction ("playbink", "Sl", opcodePlayBink); extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8eb121d37..6b06c60f5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1287,9 +1287,9 @@ namespace MWWorld } - void World::playVideo (const std::string &name) + void World::playVideo (const std::string &name, bool allowSkipping) { - mRendering->playVideo(name); + mRendering->playVideo(name, allowSkipping); } void World::stopVideo () diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1c1352913..ce0bbb1c4 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -334,7 +334,7 @@ namespace MWWorld /// 3 - enemies are nearby (not implemented) /// \todo this does not belong here - virtual void playVideo(const std::string& name); + virtual void playVideo(const std::string& name, bool allowSkipping); virtual void stopVideo(); }; } From 14d814d1d310e6dd30ef5c82abfae036af585e94 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 04:21:25 -0800 Subject: [PATCH 280/916] Avoid creating bones for NiTriShape nodes The offset specified for them can be just as easilly handled by the tag point they get connected to, and as such it's just needless extra nodes. --- components/nifogre/ogre_nif_loader.cpp | 55 ++++++++++++++++---------- components/nifogre/ogre_nif_loader.hpp | 19 +++++++-- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 3c8b3067a..e71c57efa 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -169,6 +169,8 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const for(size_t i = 0;i < ctrls.size();i++) { Nif::NiKeyframeController *kfc = ctrls[i]; + if(kfc->data.empty()) + continue; Nif::NiKeyframeData *kf = kfc->data.getPtr(); /* Get the keyframes and make sure they're sorted first to last */ @@ -183,7 +185,9 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Ogre::Bone *bone = skel->getBone(targets[i]); // NOTE: For some reason, Ogre doesn't like the node track ID being different from // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->createNodeTrack(bone->getHandle(), bone); + Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? + anim->getNodeTrack(bone->getHandle()) : + anim->createNodeTrack(bone->getHandle(), bone); const Ogre::Quaternion &startquat = bone->getInitialOrientation(); const Ogre::Vector3 &starttrans = bone->getInitialPosition(); const Ogre::Vector3 &startscale = bone->getInitialScale(); @@ -299,6 +303,9 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) { + if(node->recType == Nif::RC_NiTriShape) + return; + Ogre::Bone *bone; if(!skel->hasBone(node->name)) bone = skel->createBone(node->name); @@ -403,6 +410,9 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { + if(node->recType == Nif::RC_NiTriShape) + return false; + if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); @@ -733,7 +743,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Get the skeleton resource, so vertices can be transformed into the bones' initial state. Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); skel = skelMgr->getByName(mSkelName); - skel->touch(); // Convert vertices and normals to bone space from bind position. It would be // better to transform the bones into bind position, but there doesn't seem to @@ -967,7 +976,7 @@ public: findTriShape(mesh, node); } - void createMeshes(const Nif::Node *node, MeshPairList &meshes, int flags=0) + void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) { flags |= node->flags; @@ -1026,7 +1035,8 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(std::make_pair(mesh->getName(), shape->name)); + meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), + shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); } else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && node->recType != Nif::RC_NiRotatingParticles) @@ -1047,16 +1057,16 @@ public: NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -typedef std::map MeshPairMap; -static MeshPairMap sMeshPairMap; +typedef std::map MeshInfoMap; +static MeshInfoMap sMeshInfoMap; -MeshPairList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) { - MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName); - if(meshiter != sMeshPairMap.end()) + MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); + if(meshiter != sMeshInfoMap.end()) return meshiter->second; - MeshPairList &meshes = sMeshPairMap[name+"@skel="+skelName]; + MeshInfoList &meshes = sMeshInfoMap[name+"@skel="+skelName]; Nif::NIFFile nif(name); if (nif.numRecords() < 1) { @@ -1090,14 +1100,14 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na EntityList entitylist; std::transform(name.begin(), name.end(), name.begin(), ::tolower); - MeshPairList meshes = load(name, name, group); + MeshInfoList meshes = load(name, name, group); if(meshes.size() == 0) return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); for(size_t i = 0;i < meshes.size();i++) { - entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first)); + entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].mMeshName)); Ogre::Entity *entity = entitylist.mEntities.back(); if(!entitylist.mSkelBase && entity->hasSkeleton()) entitylist.mSkelBase = entity; @@ -1115,7 +1125,12 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) - entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); + { + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + tag->setPosition(meshes[i].mPos); + tag->setOrientation(meshes[i].mRot); + tag->setScale(Ogre::Vector3(meshes[i].mScale)); + } } } else @@ -1134,22 +1149,22 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo EntityList entitylist; std::transform(name.begin(), name.end(), name.begin(), ::tolower); - MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), group); + MeshInfoList meshes = load(name, parent->getMesh()->getSkeletonName(), group); if(meshes.size() == 0) return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = "tri "+bonename; - std::transform(filter.begin()+4, filter.end(), filter.begin()+4, ::tolower); + std::string filter = bonename; + std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower); for(size_t i = 0;i < meshes.size();i++) { - Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first); + Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - std::transform(meshes[i].second.begin(), meshes[i].second.end(), meshes[i].second.begin(), ::tolower); + std::transform(meshes[i].mTargetNode.begin(), meshes[i].mTargetNode.end(), + meshes[i].mTargetNode.begin(), ::tolower); - if(meshes[i].second.length() < filter.length() || - meshes[i].second.compare(0, filter.length(), filter) != 0) + if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) { sceneMgr->destroyEntity(ent); continue; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 47d1573fe..4ed52a84a 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -53,8 +53,21 @@ struct EntityList { }; -/** This holds a list of mesh names along with the names of their parent nodes */ -typedef std::vector< std::pair > MeshPairList; +/* This holds a list of mesh names, the names of their parent nodes, and the offset + * from their parent nodes. */ +struct MeshInfo { + std::string mMeshName; + std::string mTargetNode; + Ogre::Vector3 mPos; + Ogre::Matrix3 mRot; + float mScale; + + MeshInfo(const std::string &name, const std::string &target, + const Ogre::Vector3 &pos, const Ogre::Matrix3 &rot, float scale) + : mMeshName(name), mTargetNode(target), mPos(pos), mRot(rot), mScale(scale) + { } +}; +typedef std::vector MeshInfoList; /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into @@ -70,7 +83,7 @@ typedef std::vector< std::pair > MeshPairList; */ class NIFLoader { - static MeshPairList load(const std::string &name, const std::string &skelName, const std::string &group); + static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From 5f668976a84cbff41a948314f4e4282a8601b94d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 04:48:59 -0800 Subject: [PATCH 281/916] Improve resetting the animation position --- apps/openmw/mwrender/animation.cpp | 8 ++++---- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4cf0db3ed..4b8580467 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,6 +21,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mSkipFrame(false) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mStartPosition(0.0f) , mLastPosition(0.0f) { mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; @@ -76,7 +77,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); - mLastPosition = mNonAccumRoot->getPosition(); + mStartPosition = mNonAccumRoot->getPosition(); + mLastPosition = mStartPosition; break; } } @@ -117,9 +119,7 @@ void Animation::resetPosition(float time) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); - /* FIXME: This should be set to -mLastPosition, but without proper collision the - * model gets placed halfway into the ground. */ - mAccumRoot->setPosition(0.0f, 0.0f, 0.0f); + mAccumRoot->setPosition(mStartPosition - mLastPosition); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d1ae5af4c..73e34befe 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -39,6 +39,7 @@ protected: NifOgre::TextKeyMap mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; /* Updates the animation to the specified time, and moves the mPtr object From 05dfafa7770d01f988f8d13488ab80df88d3e016 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:09:15 -0800 Subject: [PATCH 282/916] Avoid an unnecessary lookup when moving the scene node --- apps/openmw/mwrender/renderingmanager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 71424aaed..51f1150ef 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -249,8 +249,7 @@ void RenderingManager::removeObject (const MWWorld::Ptr& ptr) void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position) { /// \todo move this to the rendering-subsystems - mRendering.getScene()->getSceneNode (ptr.getRefData().getHandle())-> - setPosition (position); + ptr.getRefData().getBaseNode()->setPosition(position); } void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale) From d3e949f5c61e8196da71c48655c67bdbbb8d2356 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:23:44 -0800 Subject: [PATCH 283/916] Make the animation text keys lower case to help lookup --- apps/openmw/mwrender/animation.cpp | 35 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4b8580467..aedc13189 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -82,6 +82,13 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } } + + NifOgre::TextKeyMap::iterator keyiter; + for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + { + std::transform(keyiter->second.begin(), keyiter->second.end(), + keyiter->second.begin(), ::tolower); + } } } @@ -124,19 +131,12 @@ void Animation::resetPosition(float time) } -struct checklow { - bool operator()(const char &a, const char &b) const - { - return ::tolower(a) == ::tolower(b); - } -}; - bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { - const std::string &start = groupname+": start"; - const std::string &startloop = groupname+": loop start"; - const std::string &stop = groupname+": stop"; - const std::string &stoploop = groupname+": loop stop"; + const std::string start = groupname+": start"; + const std::string startloop = groupname+": loop start"; + const std::string stop = groupname+": stop"; + const std::string stoploop = groupname+": loop stop"; NifOgre::TextKeyMap::const_iterator iter; for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) @@ -144,24 +144,20 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f) return true; - std::string::const_iterator strpos = iter->second.begin(); - std::string::const_iterator strend = iter->second.end(); - size_t strlen = strend-strpos; - - if(start.size() <= strlen && std::mismatch(strpos, strend, start.begin(), checklow()).first == strend) + if(start == iter->second) { times->mStart = iter->first; times->mLoopStart = iter->first; } - else if(startloop.size() <= strlen && std::mismatch(strpos, strend, startloop.begin(), checklow()).first == strend) + else if(startloop == iter->second) { times->mLoopStart = iter->first; } - else if(stoploop.size() <= strlen && std::mismatch(strpos, strend, stoploop.begin(), checklow()).first == strend) + else if(stoploop == iter->second) { times->mLoopStop = iter->first; } - else if(stop.size() <= strlen && std::mismatch(strpos, strend, stop.begin(), checklow()).first == strend) + else if(stop == iter->second) { times->mStop = iter->first; if(times->mLoopStop < 0.0f) @@ -179,6 +175,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) GroupTimes times; times.mLoops = loops; + std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); if(groupname == "all") { times.mStart = times.mLoopStart = 0.0f; From d8dbd5e206c8c028c6d52ee72d498bd5d97c5b49 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 05:56:03 -0800 Subject: [PATCH 284/916] Store text key iterators for the start and stop times --- apps/openmw/mwrender/animation.cpp | 84 +++++++++++++++--------------- apps/openmw/mwrender/animation.hpp | 26 ++++----- 2 files changed, 54 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index aedc13189..b4bfd0684 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,18 +16,16 @@ namespace MWRender Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mInsert(NULL) - , mTime(0.0f) - , mAnimState(NULL) - , mSkipFrame(false) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mStartPosition(0.0f) , mLastPosition(0.0f) + , mTime(0.0f) + , mCurGroup(mTextKeys.end()) + , mNextGroup(mTextKeys.end()) + , mAnimState(NULL) + , mSkipFrame(false) { - mCurGroup.mStart = mCurGroup.mLoopStart = 0.0f; - mCurGroup.mLoopStop = mCurGroup.mStop = 0.0f; - mNextGroup.mStart = mNextGroup.mLoopStart = 0.0f; - mNextGroup.mLoopStop = mNextGroup.mStop = 0.0f; } Animation::~Animation() @@ -74,9 +72,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); + mNextGroup = mCurGroup = GroupTimes(mTextKeys.end()); + mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mStartPosition = mNonAccumRoot->getPosition(); mLastPosition = mStartPosition; break; @@ -141,60 +142,57 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim NifOgre::TextKeyMap::const_iterator iter; for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) { - if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f) - return true; - if(start == iter->second) { - times->mStart = iter->first; - times->mLoopStart = iter->first; + times->mStart = iter; + times->mLoopStart = iter; } else if(startloop == iter->second) - { - times->mLoopStart = iter->first; - } + times->mLoopStart = iter; else if(stoploop == iter->second) - { - times->mLoopStop = iter->first; - } + times->mLoopStop = iter; else if(stop == iter->second) { - times->mStop = iter->first; - if(times->mLoopStop < 0.0f) - times->mLoopStop = iter->first; - break; + times->mStop = iter; + if(times->mLoopStop == mTextKeys.end()) + times->mLoopStop = iter; + return (times->mStart != mTextKeys.end()); } } - return (times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f); + return false; } void Animation::playGroup(std::string groupname, int mode, int loops) { - GroupTimes times; + if(mTextKeys.size() == 0) + { + std::cerr<< "Trying to animate an unanimate object" <first; + times.mStart = times.mLoopStart = mTextKeys.begin(); + times.mLoopStop = times.mStop = mTextKeys.end(); } else if(!findGroupTimes(groupname, ×)) - throw std::runtime_error("Failed to find animation group "+groupname); + { + std::cerr<< "Failed to find animation group "< 0) mNextGroup = times; else { mCurGroup = times; - mNextGroup = GroupTimes(); - mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); + mNextGroup = GroupTimes(mTextKeys.end()); + mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; resetPosition(mTime); } } @@ -210,28 +208,28 @@ void Animation::runAnimation(float timepassed) { mTime += timepassed; recheck: - if(mTime >= mCurGroup.mLoopStop) + if(mTime >= mCurGroup.mLoopStop->first) { if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; - updatePosition(mCurGroup.mLoopStop); - mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart; - resetPosition(mCurGroup.mLoopStart); + updatePosition(mCurGroup.mLoopStop->first); + mTime = mTime - mCurGroup.mLoopStop->first + mCurGroup.mLoopStart->first; + resetPosition(mCurGroup.mLoopStart->first); goto recheck; } - else if(mTime >= mCurGroup.mStop) + else if(mTime >= mCurGroup.mStop->first) { if(mNextGroup.mLoops > 0) { - updatePosition(mCurGroup.mStop); - mTime = mTime - mCurGroup.mStop + mNextGroup.mStart; - resetPosition(mNextGroup.mStart); + updatePosition(mCurGroup.mStop->first); + mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; + resetPosition(mNextGroup.mStart->first); mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); + mNextGroup = GroupTimes(mTextKeys.end()); goto recheck; } - mTime = mCurGroup.mStop; + mTime = mCurGroup.mStop->first; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 73e34befe..44a2eaf3e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -11,15 +11,15 @@ namespace MWRender class Animation { struct GroupTimes { - float mStart; - float mStop; - float mLoopStart; - float mLoopStop; + NifOgre::TextKeyMap::const_iterator mStart; + NifOgre::TextKeyMap::const_iterator mStop; + NifOgre::TextKeyMap::const_iterator mLoopStart; + NifOgre::TextKeyMap::const_iterator mLoopStop; size_t mLoops; - GroupTimes() - : mStart(-1.0f), mStop(-1.0f), mLoopStart(-1.0f), mLoopStop(-1.0f), + GroupTimes(NifOgre::TextKeyMap::const_iterator iter) + : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), mLoops(0) { } }; @@ -28,13 +28,6 @@ protected: MWWorld::Ptr mPtr; Ogre::SceneNode* mInsert; - float mTime; - GroupTimes mCurGroup; - GroupTimes mNextGroup; - Ogre::AnimationState *mAnimState; - - bool mSkipFrame; - NifOgre::EntityList mEntityList; NifOgre::TextKeyMap mTextKeys; Ogre::Bone *mAccumRoot; @@ -42,6 +35,13 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + float mTime; + GroupTimes mCurGroup; + GroupTimes mNextGroup; + Ogre::AnimationState *mAnimState; + + bool mSkipFrame; + /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ void updatePosition(float time); From c2901fe6ccb70b5511e631aab98946ac70d35f60 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Mon, 7 Jan 2013 18:16:50 +0000 Subject: [PATCH 285/916] added addsoulgem scripting function --- apps/openmw/mwscript/docs/vmformat.txt | 4 ++- apps/openmw/mwscript/miscextensions.cpp | 33 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 89cacf65c..8fd65bf8a 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -306,5 +306,7 @@ op 0x20001ef: GetCurrentAIPackage op 0x20001f0: GetCurrentAIPackage, explicit reference op 0x20001f1: GetDetected op 0x20001f2: GetDetected, explicit reference +op 0x20001f3: AddSoulGem +op 0x20001f4: AddSoulGem, explicit reference -opcodes 0x20001f3-0x3ffffff unused +opcodes 0x20001f5-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index b687471aa..ff273a333 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -14,6 +14,8 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -305,6 +307,32 @@ namespace MWScript MWMechanics::EffectKey(key)).mMagnitude > 0); } }; + + template + class OpAddSoulGem : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string creature = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string gem = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), gem); + + ref.getPtr().getRefData().setCount (1); + + ref.getPtr().getCellRef().mSoul = creature; + + MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); + + } + }; template class OpGetAttacked : public Interpreter::Opcode0 @@ -414,6 +442,8 @@ namespace MWScript const int opcodeGetLockedExplicit = 0x20001c8; const int opcodeGetEffect = 0x20001cf; const int opcodeGetEffectExplicit = 0x20001d0; + const int opcodeAddSoulGem = 0x20001f3; + const int opcodeAddSoulGemExplicit = 0x20001f4; const int opcodeGetAttacked = 0x20001d3; const int opcodeGetAttackedExplicit = 0x20001d4; const int opcodeGetWeaponDrawn = 0x20001d7; @@ -452,6 +482,7 @@ namespace MWScript extensions.registerInstruction ("wakeuppc", "", opcodeWakeUpPc); extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); + extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit); extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit); @@ -485,6 +516,8 @@ namespace MWScript interpreter.installSegment5 (opcodeGetLockedExplicit, new OpGetLocked); interpreter.installSegment5 (opcodeGetEffect, new OpGetEffect); interpreter.installSegment5 (opcodeGetEffectExplicit, new OpGetEffect); + interpreter.installSegment5 (opcodeAddSoulGem, new OpAddSoulGem); + interpreter.installSegment5 (opcodeAddSoulGemExplicit, new OpAddSoulGem); interpreter.installSegment5 (opcodeGetAttacked, new OpGetAttacked); interpreter.installSegment5 (opcodeGetAttackedExplicit, new OpGetAttacked); interpreter.installSegment5 (opcodeGetWeaponDrawn, new OpGetWeaponDrawn); From 4c5ed43cc9cd94e4f4438da43813fc8939d07b6d Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Mon, 7 Jan 2013 21:08:04 +0000 Subject: [PATCH 286/916] added removesoulgem, and fixed addsoulgem --- apps/openmw/mwscript/docs/vmformat.txt | 4 ++- apps/openmw/mwscript/miscextensions.cpp | 38 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 8fd65bf8a..f0a346c9d 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -308,5 +308,7 @@ op 0x20001f1: GetDetected op 0x20001f2: GetDetected, explicit reference op 0x20001f3: AddSoulGem op 0x20001f4: AddSoulGem, explicit reference +op 0x20001f5: RemoveSoulGem +op 0x20001f6: RemoveSoulGem, explicit reference -opcodes 0x20001f5-0x3ffffff unused +opcodes 0x20001f7-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index ff273a333..9ca3503cf 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -322,6 +322,9 @@ namespace MWScript std::string gem = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); + + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + store.get().find(creature); // This line throws an exception if it can't find the creature MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), gem); @@ -334,6 +337,36 @@ namespace MWScript } }; + template + class OpRemoveSoulGem : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + + MWWorld::Ptr ptr = R()(runtime); + + std::string soul = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); + + + for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) + { + if (::Misc::StringUtils::ciEqual(iter->getCellRef().mSoul, soul)) + { + if (iter->getRefData().getCount() <= 1) + iter->getRefData().setCount (0); + else + iter->getRefData().setCount (iter->getRefData().getCount() - 1); + break; + } + } + } + }; + template class OpGetAttacked : public Interpreter::Opcode0 { @@ -444,6 +477,8 @@ namespace MWScript const int opcodeGetEffectExplicit = 0x20001d0; const int opcodeAddSoulGem = 0x20001f3; const int opcodeAddSoulGemExplicit = 0x20001f4; + const int opcodeRemoveSoulGem = 0x20001f5; + const int opcodeRemoveSoulGemExplicit = 0x20001f6; const int opcodeGetAttacked = 0x20001d3; const int opcodeGetAttackedExplicit = 0x20001d4; const int opcodeGetWeaponDrawn = 0x20001d7; @@ -483,6 +518,7 @@ namespace MWScript extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); + extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit); extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit); @@ -518,6 +554,8 @@ namespace MWScript interpreter.installSegment5 (opcodeGetEffectExplicit, new OpGetEffect); interpreter.installSegment5 (opcodeAddSoulGem, new OpAddSoulGem); interpreter.installSegment5 (opcodeAddSoulGemExplicit, new OpAddSoulGem); + interpreter.installSegment5 (opcodeRemoveSoulGem, new OpRemoveSoulGem); + interpreter.installSegment5 (opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem); interpreter.installSegment5 (opcodeGetAttacked, new OpGetAttacked); interpreter.installSegment5 (opcodeGetAttackedExplicit, new OpGetAttacked); interpreter.installSegment5 (opcodeGetWeaponDrawn, new OpGetWeaponDrawn); From 9ee823d8f847c30629af818df9907973e9da5358 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Mon, 7 Jan 2013 21:09:03 +0000 Subject: [PATCH 287/916] fixed typo in vmformat.txt --- apps/openmw/mwscript/docs/vmformat.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index f0a346c9d..66be100e5 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -301,7 +301,7 @@ op 0x20001ea: LowerRank op 0x20001eb: LowerRank, explicit op 0x20001ec: GetPCCrimeLevel op 0x20001ed: SetPCCrimeLevel -op 0x20001ee: SetPCCrimeLevel +op 0x20001ee: ModPCCrimeLevel op 0x20001ef: GetCurrentAIPackage op 0x20001f0: GetCurrentAIPackage, explicit reference op 0x20001f1: GetDetected From 2a9dc5ad94a48353b816f3056ce4c3326e2a7bef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 7 Jan 2013 21:00:21 -0800 Subject: [PATCH 288/916] Ensure mCurGroup always has valid iterators, and only get the animation state when animation keys exist --- apps/openmw/mwrender/animation.cpp | 34 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b4bfd0684..6da3ad583 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -49,17 +49,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) - { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); - state->setLoop(false); - if(!mAnimState) - mAnimState = state; - } - Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); @@ -72,7 +61,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(!data.isEmpty()) { mTextKeys = Ogre::any_cast(data); - mNextGroup = mCurGroup = GroupTimes(mTextKeys.end()); + mNextGroup = mCurGroup = GroupTimes(mTextKeys.begin()); mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); @@ -84,11 +73,23 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } } - NifOgre::TextKeyMap::iterator keyiter; - for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + if(mTextKeys.size() > 0) { - std::transform(keyiter->second.begin(), keyiter->second.end(), - keyiter->second.begin(), ::tolower); + NifOgre::TextKeyMap::iterator keyiter; + for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) + std::transform(keyiter->second.begin(), keyiter->second.end(), + keyiter->second.begin(), ::tolower); + + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setEnabled(true); + state->setLoop(false); + if(!mAnimState) + mAnimState = state; + } } } } @@ -179,6 +180,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) { times.mStart = times.mLoopStart = mTextKeys.begin(); times.mLoopStop = times.mStop = mTextKeys.end(); + times.mLoopStop--; times.mStop--; } else if(!findGroupTimes(groupname, ×)) { From 86f691d3d59023d9c3fdef0550bd2a08282f0df6 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 7 Jan 2013 22:48:24 -0800 Subject: [PATCH 289/916] split MWWord::World::update into multiple functions --- apps/openmw/mwworld/worldimp.cpp | 258 +++++++++++++++++-------------- apps/openmw/mwworld/worldimp.hpp | 7 + 2 files changed, 152 insertions(+), 113 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4f60f6ef4..26614f3e1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -884,8 +884,6 @@ namespace MWWorld void World::update (float duration, bool paused) { - /// \todo split this function up into subfunctions - mWorldScene->update (duration, paused); float pitch, yaw; @@ -895,6 +893,13 @@ namespace MWWorld mWeatherManager->update (duration); + performUpdateSceneQueries (); + + updateWindowManager (); + } + + void World::updateWindowManager () + { // inform the GUI about focused object MWWorld::Ptr object = searchPtrViaHandle(mFacedHandle); @@ -918,7 +923,10 @@ namespace MWWorld screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); } } + } + void World::performUpdateSceneQueries () + { if (!mRendering->occlusionQuerySupported()) { // cast a ray from player to sun to detect if the sun is visible @@ -937,121 +945,145 @@ namespace MWWorld MWRender::OcclusionQuery* query = mRendering->getOcclusionQuery(); if (!query->occlusionTestPending()) { - // get result of last query - if (mNumFacing == 0) mFacedHandle = ""; - else if (mNumFacing == 1) - { - bool result = query->getTestResult(); - mFacedHandle = result ? mFaced1Name : ""; - } - else if (mNumFacing == 2) - { - bool result = query->getTestResult(); - mFacedHandle = result ? mFaced2Name : mFaced1Name; - } - - // send new query - // figure out which object we want to test against - std::vector < std::pair < float, std::string > > results; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - float x, y; - MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - results = mPhysics->getFacedObjects(x, y); - } - else - results = mPhysics->getFacedObjects(); - - // ignore the player and other things we're not interested in - std::vector < std::pair < float, std::string > >::iterator it = results.begin(); - while (it != results.end()) - { - if ( (*it).second.find("HeightField") != std::string::npos // not interested in terrain - || getPtrViaHandle((*it).second) == mPlayer->getPlayer() ) // not interested in player (unless you want to talk to yourself) - { - it = results.erase(it); - } - else - ++it; - } - - if (results.size() == 0) - { - mNumFacing = 0; - } - else if (results.size() == 1) - { - mFaced1 = getPtrViaHandle(results.front().second); - mFaced1Name = results.front().second; - mNumFacing = 1; - - btVector3 p; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - float x, y; - MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - p = mPhysics->getRayPoint(results.front().first, x, y); - } - else - p = mPhysics->getRayPoint(results.front().first); - Ogre::Vector3 pos(p.x(), p.z(), -p.y()); - Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); - - //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; - //std::cout << "Type 1 " << mFaced1.getTypeName() << std::endl; - - query->occlusionTest(pos, node); - } - else - { - mFaced1Name = results.front().second; - mFaced2Name = results[1].second; - mFaced1 = getPtrViaHandle(results.front().second); - mFaced2 = getPtrViaHandle(results[1].second); - mNumFacing = 2; - - btVector3 p; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - float x, y; - MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - p = mPhysics->getRayPoint(results[1].first, x, y); - } - else - p = mPhysics->getRayPoint(results[1].first); - Ogre::Vector3 pos(p.x(), p.z(), -p.y()); - Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); - Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); - - // no need to test if the first node is not occluder - if (!query->isPotentialOccluder(node1) && (mFaced1.getTypeName().find("Static") == std::string::npos)) - { - mFacedHandle = mFaced1Name; - //std::cout << "node1 Not an occluder" << std::endl; - return; - } - - // no need to test if the second object is static (thus cannot be activated) - if (mFaced2.getTypeName().find("Static") != std::string::npos) - { - mFacedHandle = mFaced1Name; - return; - } - - // work around door problems - if (mFaced1.getTypeName().find("Static") != std::string::npos - && mFaced2.getTypeName().find("Door") != std::string::npos) - { - mFacedHandle = mFaced2Name; - return; - } - - query->occlusionTest(pos, node2); - } + processFacedQueryResults (query); + beginFacedQueryProcess (query); } } } + void World::processFacedQueryResults (MWRender::OcclusionQuery* query) + { + // get result of last query + if (mNumFacing == 0) + { + mFacedHandle = ""; + } + else if (mNumFacing == 1) + { + bool result = query->getTestResult(); + mFacedHandle = result ? mFaced1Name : ""; + } + else if (mNumFacing == 2) + { + bool result = query->getTestResult(); + mFacedHandle = result ? mFaced2Name : mFaced1Name; + } + } + + void World::beginFacedQueryProcess (MWRender::OcclusionQuery* query) + { + // send new query + // figure out which object we want to test against + std::vector < std::pair < float, std::string > > results; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + float x, y; + MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); + results = mPhysics->getFacedObjects(x, y); + } + else + { + results = mPhysics->getFacedObjects(); + } + + // ignore the player and other things we're not interested in + std::vector < std::pair < float, std::string > >::iterator it = results.begin(); + while (it != results.end()) + { + if ( (*it).second.find("HeightField") != std::string::npos // not interested in terrain + || getPtrViaHandle((*it).second) == mPlayer->getPlayer() ) // not interested in player (unless you want to talk to yourself) + { + it = results.erase(it); + } + else + ++it; + } + + if (results.size() == 0) + { + mNumFacing = 0; + } + else if (results.size() == 1) + { + beginSingleFacedQueryProcess (query, results); + } + else + { + beginDoubleFacedQueryProcess (query, results); + } + } + + void World::beginSingleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results) + { + mFaced1 = getPtrViaHandle(results.front().second); + mFaced1Name = results.front().second; + mNumFacing = 1; + + btVector3 p; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + float x, y; + MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); + p = mPhysics->getRayPoint(results.front().first, x, y); + } + else + p = mPhysics->getRayPoint(results.front().first); + Ogre::Vector3 pos(p.x(), p.z(), -p.y()); + Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); + + //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; + //std::cout << "Type 1 " << mFaced1.getTypeName() << std::endl; + + query->occlusionTest(pos, node); + } + + void World::beginDoubleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results) + { + mFaced1Name = results.at (0).second; + mFaced2Name = results.at (1).second; + mFaced1 = getPtrViaHandle(results.at (0).second); + mFaced2 = getPtrViaHandle(results.at (1).second); + mNumFacing = 2; + + btVector3 p; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + float x, y; + MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); + p = mPhysics->getRayPoint(results.at (1).first, x, y); + } + else + p = mPhysics->getRayPoint(results.at (1).first); + Ogre::Vector3 pos(p.x(), p.z(), -p.y()); + Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); + Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); + + // no need to test if the first node is not occluder + if (!query->isPotentialOccluder(node1) && (mFaced1.getTypeName().find("Static") == std::string::npos)) + { + mFacedHandle = mFaced1Name; + //std::cout << "node1 Not an occluder" << std::endl; + return; + } + + // no need to test if the second object is static (thus cannot be activated) + if (mFaced2.getTypeName().find("Static") != std::string::npos) + { + mFacedHandle = mFaced1Name; + return; + } + + // work around door problems + if (mFaced1.getTypeName().find("Static") != std::string::npos + && mFaced2.getTypeName().find("Door") != std::string::npos) + { + mFacedHandle = mFaced2Name; + return; + } + + query->occlusionTest(pos, node2); + } + bool World::isCellExterior() const { Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d29adebf4..a60332e26 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -90,6 +90,13 @@ namespace MWWorld virtual void copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos); + void updateWindowManager (); + void performUpdateSceneQueries (); + void processFacedQueryResults (MWRender::OcclusionQuery* query); + void beginFacedQueryProcess (MWRender::OcclusionQuery* query); + void beginSingleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results); + void beginDoubleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results); + public: World (OEngine::Render::OgreRenderer& renderer, From 0108be2e4f4e2e9257622667d3ecbf1666a29e1e Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 7 Jan 2013 23:00:00 -0800 Subject: [PATCH 290/916] updated MWWorld::PhysicsSystem::getFacedXXX functions * changed the names and return values to be consistent * made the distance to search a parameter * change the distance returned to world units instead of percentage of query distance --- apps/openmw/mwworld/physicssystem.cpp | 35 ++++++++++++++++++--------- apps/openmw/mwworld/physicssystem.hpp | 7 +++--- apps/openmw/mwworld/worldimp.cpp | 12 ++++----- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5359c4eb2..9e2e94143 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -43,7 +43,7 @@ namespace MWWorld return mEngine; } - std::pair PhysicsSystem::getFacedHandle (MWWorld::World& world) + std::pair PhysicsSystem::getFacedHandle (MWWorld::World& world, float queryDistance) { btVector3 dir(0, 1, 0); dir = dir.rotate(btVector3(1, 0, 0), mPlayerData.pitch); @@ -56,11 +56,14 @@ namespace MWWorld mPlayerData.eyepos.z); origin += dir * 5; - btVector3 dest = origin + dir * 500; - return mEngine->rayTest(origin, dest); + btVector3 dest = origin + dir * queryDistance; + std::pair result; + /*auto*/ result = mEngine->rayTest(origin, dest); + result.second *= queryDistance; + return std::make_pair (result.second, result.first); } - std::vector < std::pair > PhysicsSystem::getFacedObjects () + std::vector < std::pair > PhysicsSystem::getFacedHandles (float queryDistance) { btVector3 dir(0, 1, 0); dir = dir.rotate(btVector3(1, 0, 0), mPlayerData.pitch); @@ -73,22 +76,32 @@ namespace MWWorld mPlayerData.eyepos.z); origin += dir * 5; - btVector3 dest = origin + dir * 500; - return mEngine->rayTest2(origin, dest); + btVector3 dest = origin + dir * queryDistance; + std::vector < std::pair > results; + /* auto */ results = mEngine->rayTest2(origin, dest); + std::vector < std::pair >::iterator i; + for (/* auto */ i = results.begin (); i != results.end (); ++i) + i->first *= queryDistance; + return results; } - std::vector < std::pair > PhysicsSystem::getFacedObjects (float mouseX, float mouseY) + std::vector < std::pair > PhysicsSystem::getFacedHandles (float mouseX, float mouseY, float queryDistance) { Ray ray = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); Ogre::Vector3 from = ray.getOrigin(); - Ogre::Vector3 to = ray.getPoint(500); /// \todo make this distance (ray length) configurable + Ogre::Vector3 to = ray.getPoint(queryDistance); btVector3 _from, _to; // OGRE to MW coordinates _from = btVector3(from.x, -from.z, from.y); _to = btVector3(to.x, -to.z, to.y); - return mEngine->rayTest2(_from,_to); + std::vector < std::pair > results; + /* auto */ results = mEngine->rayTest2(_from,_to); + std::vector < std::pair >::iterator i; + for (/* auto */ i = results.begin (); i != results.end (); ++i) + i->first *= queryDistance; + return results; } void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) @@ -110,7 +123,7 @@ namespace MWWorld Ray centerRay = mRender.getCamera()->getCameraToViewportRay( mRender.getViewport()->getWidth()/2, mRender.getViewport()->getHeight()/2); - btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); /// \todo make this distance (ray length) configurable + btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); return result; } @@ -118,7 +131,7 @@ namespace MWWorld { //get a ray pointing to the center of the viewport Ray centerRay = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); - btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); /// \todo make this distance (ray length) configurable + btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); return result; } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 8bd73fd6c..81715c31e 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -41,14 +41,13 @@ namespace MWWorld bool toggleCollisionMode(); - std::pair getFacedHandle (MWWorld::World& world); + std::pair getFacedHandle (MWWorld::World& world, float queryDistance); + std::vector < std::pair > getFacedHandles (float queryDistance); + std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); btVector3 getRayPoint(float extent); btVector3 getRayPoint(float extent, float mouseX, float mouseY); - std::vector < std::pair > getFacedObjects (); - - std::vector < std::pair > getFacedObjects (float mouseX, float mouseY); // cast ray, return true if it hit something bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 26614f3e1..09c48bd13 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -577,13 +577,13 @@ namespace MWWorld { if (!mRendering->occlusionQuerySupported()) { - std::pair result = mPhysics->getFacedHandle (*this); + std::pair result = mPhysics->getFacedHandle (*this, 500); - if (result.first.empty() || - result.second>getStore().get().find ("iMaxActivateDist")->getInt()) + if (result.second.empty() || + result.first>getStore().get().find ("iMaxActivateDist")->getInt()) return ""; - return result.first; + return result.second; } else { @@ -979,11 +979,11 @@ namespace MWWorld { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - results = mPhysics->getFacedObjects(x, y); + results = mPhysics->getFacedHandles(x, y, 500); } else { - results = mPhysics->getFacedObjects(); + results = mPhysics->getFacedHandles(500); } // ignore the player and other things we're not interested in From 05dad29005c9651829c7695cc3da8a6bf4b2ee68 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 7 Jan 2013 23:11:15 -0800 Subject: [PATCH 291/916] update MWWord::World to track distances while performing occlusion queries. This allows checking the activation distance against what is stored in GameSettings. Experimentation suggests that a second distance is required for NPCs. --- apps/openmw/mwworld/worldimp.cpp | 12 ++++++++++++ apps/openmw/mwworld/worldimp.hpp | 3 +++ 2 files changed, 15 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 09c48bd13..002ffcd93 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -587,6 +587,9 @@ namespace MWWorld } else { + if (mFacedDistance > result.first>getStore().get().find ("iMaxActivateDist")->getInt()) + return ""; + // updated every few frames in update() return mFacedHandle; } @@ -957,16 +960,19 @@ namespace MWWorld if (mNumFacing == 0) { mFacedHandle = ""; + mFacedDistance = FLT_MAX; } else if (mNumFacing == 1) { bool result = query->getTestResult(); mFacedHandle = result ? mFaced1Name : ""; + mFacedDistance = result ? mFaced1Distance : FLT_MAX; } else if (mNumFacing == 2) { bool result = query->getTestResult(); mFacedHandle = result ? mFaced2Name : mFaced1Name; + mFacedDistance = result ? mFaced1Distance : mFaced1Distance; } } @@ -1017,6 +1023,7 @@ namespace MWWorld { mFaced1 = getPtrViaHandle(results.front().second); mFaced1Name = results.front().second; + mFaced1Distance = results.front().first; mNumFacing = 1; btVector3 p; @@ -1041,6 +1048,8 @@ namespace MWWorld { mFaced1Name = results.at (0).second; mFaced2Name = results.at (1).second; + mFaced1Distance = results.at (0).first; + mFaced2Distance = results.at (1).first; mFaced1 = getPtrViaHandle(results.at (0).second); mFaced2 = getPtrViaHandle(results.at (1).second); mNumFacing = 2; @@ -1062,6 +1071,7 @@ namespace MWWorld if (!query->isPotentialOccluder(node1) && (mFaced1.getTypeName().find("Static") == std::string::npos)) { mFacedHandle = mFaced1Name; + mFacedDistance = mFaced1Distance; //std::cout << "node1 Not an occluder" << std::endl; return; } @@ -1070,6 +1080,7 @@ namespace MWWorld if (mFaced2.getTypeName().find("Static") != std::string::npos) { mFacedHandle = mFaced1Name; + mFacedDistance = mFaced1Distance; return; } @@ -1078,6 +1089,7 @@ namespace MWWorld && mFaced2.getTypeName().find("Door") != std::string::npos) { mFacedHandle = mFaced2Name; + mFacedDistance = mFaced2Distance; return; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a60332e26..de6689deb 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -72,10 +72,13 @@ namespace MWWorld Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cellStore); std::string mFacedHandle; + float mFacedDistance; Ptr mFaced1; Ptr mFaced2; std::string mFaced1Name; std::string mFaced2Name; + float mFaced1Distance; + float mFaced2Distance; int mNumFacing; std::map mFallback; From b9fbd6ae4b4be8319eb31596a6aa77e598cd90ae Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 7 Jan 2013 23:27:37 -0800 Subject: [PATCH 292/916] Factored faced object lookups into MWRender::World * Renamed MWWorld::World::getFacedHandle to getFacedObject. * Changed it to return an object pointer * Updated clients to use return object directly. --- apps/openmw/engine.cpp | 7 +------ apps/openmw/mwbase/world.hpp | 4 ++-- apps/openmw/mwgui/hud.cpp | 3 +-- apps/openmw/mwgui/tooltips.cpp | 3 +-- apps/openmw/mwworld/worldimp.cpp | 32 +++++++++++++++----------------- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 6 files changed, 22 insertions(+), 31 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index aadeb7f3a..fcfaed47d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -427,12 +427,7 @@ void OMW::Engine::activate() if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; - std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); - - if (handle.empty()) - return; - - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle (handle); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject(); if (ptr.isEmpty()) return; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cc625b306..6f7b6e61a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -199,8 +199,8 @@ namespace MWBase virtual void markCellAsUnchanged() = 0; - virtual std::string getFacedHandle() = 0; - ///< Return handle of the object the player is looking at + virtual MWWorld::Ptr getFacedObject() = 0; + ///< Return pointer to the object the player is looking at, if it is within activation range virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 689baf488..5ea1d1338 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -244,8 +244,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) ) return; - std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); - MWWorld::Ptr object = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle); + MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 97df211ac..c7acf568d 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -80,9 +80,8 @@ void ToolTips::onFrame(float frameDuration) || (mWindowManager->getMode() == GM_Container) || (mWindowManager->getMode() == GM_Inventory))) { - std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); + mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); - mFocusObject = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle); if (mFocusObject.isEmpty ()) return; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 002ffcd93..a893a6776 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -573,26 +573,24 @@ namespace MWWorld return mWorldScene->markCellAsUnchanged(); } - std::string World::getFacedHandle() + MWWorld::Ptr World::getFacedObject() { + std::pair result; + if (!mRendering->occlusionQuerySupported()) - { - std::pair result = mPhysics->getFacedHandle (*this, 500); - - if (result.second.empty() || - result.first>getStore().get().find ("iMaxActivateDist")->getInt()) - return ""; - - return result.second; - } + result = mPhysics->getFacedHandle (*this, 500); else - { - if (mFacedDistance > result.first>getStore().get().find ("iMaxActivateDist")->getInt()) - return ""; + result = std::make_pair (mFacedDistance, mFacedHandle); - // updated every few frames in update() - return mFacedHandle; - } + if (result.second.empty()) + return MWWorld::Ptr (); + + float ActivationDistance = getStore().get().find ("iMaxActivateDist")->getInt(); + + if (result.first > ActivationDistance) + return MWWorld::Ptr (); + + return searchPtrViaHandle (result.second); } void World::deleteObject (const Ptr& ptr) @@ -904,7 +902,7 @@ namespace MWWorld void World::updateWindowManager () { // inform the GUI about focused object - MWWorld::Ptr object = searchPtrViaHandle(mFacedHandle); + MWWorld::Ptr object = getFacedObject (); MWBase::Environment::get().getWindowManager()->setFocusObject(object); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index de6689deb..62fb1d89a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -227,8 +227,8 @@ namespace MWWorld virtual void markCellAsUnchanged(); - virtual std::string getFacedHandle(); - ///< Return handle of the object the player is looking at + virtual MWWorld::Ptr getFacedObject(); + ///< Return pointer to the object the player is looking at, if it is within activation range virtual void deleteObject (const Ptr& ptr); From b3932e3deae509f5d82647e308cc313ac17817e5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 7 Jan 2013 23:40:17 -0800 Subject: [PATCH 293/916] added a separate activation distance for NPCs --- apps/openmw/mwworld/worldimp.cpp | 32 +++++++++++++++++++++++++++----- apps/openmw/mwworld/worldimp.hpp | 4 ++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a893a6776..739d0daab 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -573,24 +573,46 @@ namespace MWWorld return mWorldScene->markCellAsUnchanged(); } + float World::getMaxActivationDistance () + { + return (std::max) (getNpcActivationDistance (), getObjectActivationDistance ()); + } + + float World::getNpcActivationDistance () + { + return getStore().get().find ("iMaxActivateDist")->getInt()*5/4; + } + + float World::getObjectActivationDistance () + { + return getStore().get().find ("iMaxActivateDist")->getInt(); + } + MWWorld::Ptr World::getFacedObject() { std::pair result; if (!mRendering->occlusionQuerySupported()) - result = mPhysics->getFacedHandle (*this, 500); + result = mPhysics->getFacedHandle (*this, getMaxActivationDistance ()); else result = std::make_pair (mFacedDistance, mFacedHandle); if (result.second.empty()) return MWWorld::Ptr (); - float ActivationDistance = getStore().get().find ("iMaxActivateDist")->getInt(); + MWWorld::Ptr object = searchPtrViaHandle (result.second); + + float ActivationDistance; + + if (object.getTypeName ().find("NPC") != std::string::npos) + ActivationDistance = getNpcActivationDistance (); + else + ActivationDistance = getObjectActivationDistance (); if (result.first > ActivationDistance) return MWWorld::Ptr (); - return searchPtrViaHandle (result.second); + return object; } void World::deleteObject (const Ptr& ptr) @@ -983,11 +1005,11 @@ namespace MWWorld { float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); - results = mPhysics->getFacedHandles(x, y, 500); + results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()); } else { - results = mPhysics->getFacedHandles(500); + results = mPhysics->getFacedHandles(getMaxActivationDistance ()); } // ignore the player and other things we're not interested in diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 62fb1d89a..a1ba6fcde 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -100,6 +100,10 @@ namespace MWWorld void beginSingleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results); void beginDoubleFacedQueryProcess (MWRender::OcclusionQuery* query, std::vector < std::pair < float, std::string > > const & results); + float getMaxActivationDistance (); + float getNpcActivationDistance (); + float getObjectActivationDistance (); + public: World (OEngine::Render::OgreRenderer& renderer, From e18cf452d4728adad7bdd2faad870399c7fe05b9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 8 Jan 2013 13:24:40 +0100 Subject: [PATCH 294/916] Updated shiny again. Some recent changes were accidently overwritten by eduard on 12/30/2012 --- .gitmodules | 1 - extern/shiny/CMakeLists.txt | 3 + extern/shiny/Main/Factory.cpp | 2 +- extern/shiny/Main/MaterialInstance.cpp | 8 +- extern/shiny/Main/ScriptLoader.cpp | 110 ++++++++++++------------- extern/shiny/Main/ScriptLoader.hpp | 42 +++++----- 6 files changed, 85 insertions(+), 81 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 8b1378917..000000000 --- a/.gitmodules +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extern/shiny/CMakeLists.txt b/extern/shiny/CMakeLists.txt index c27850ed6..603336413 100644 --- a/extern/shiny/CMakeLists.txt +++ b/extern/shiny/CMakeLists.txt @@ -70,3 +70,6 @@ endif() link_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE) +set(SHINY_OGREPLATFORM_LIBRARY ${SHINY_OGREPLATFORM_LIBRARY} PARENT_SCOPE) diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 678ee25c9..82d664811 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -224,7 +224,7 @@ namespace sh if (!mShadersEnabled) newInstance.setShadersEnabled (false); - newInstance.setSourceFile (it->second->m_fileName); + newInstance.setSourceFile (it->second->mFileName); std::vector props = it->second->getChildren(); for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) diff --git a/extern/shiny/Main/MaterialInstance.cpp b/extern/shiny/Main/MaterialInstance.cpp index 3abc781f6..0f8bcdda7 100644 --- a/extern/shiny/Main/MaterialInstance.cpp +++ b/extern/shiny/Main/MaterialInstance.cpp @@ -72,6 +72,8 @@ namespace sh allowFixedFunction = retrieveValue(getProperty("allow_fixed_function"), NULL).get(); } + bool useShaders = mShadersEnabled || !allowFixedFunction; + // get passes of the top-most parent PassVector passes = getPasses(); if (passes.size() == 0) @@ -91,7 +93,7 @@ namespace sh // create or retrieve shaders bool hasVertex = it->hasProperty("vertex_program"); bool hasFragment = it->hasProperty("fragment_program"); - if (mShadersEnabled || !allowFixedFunction) + if (useShaders) { it->setContext(context); it->mShaderProperties.setContext(context); @@ -144,7 +146,7 @@ namespace sh bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); if ( (foundVertex || foundFragment) - || (((!mShadersEnabled || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue(texIt->getProperty("create_in_ffp"), this).get())) + || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue(texIt->getProperty("create_in_ffp"), this).get())) { boost::shared_ptr texUnit = pass->createTextureUnitState (); texIt->copyAll (texUnit.get(), context); @@ -152,7 +154,7 @@ namespace sh mTexUnits.push_back(texUnit); // set texture unit indices (required by GLSL) - if (mShadersEnabled && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL) + if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL) { pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); diff --git a/extern/shiny/Main/ScriptLoader.cpp b/extern/shiny/Main/ScriptLoader.cpp index a8971dc87..93d728b02 100644 --- a/extern/shiny/Main/ScriptLoader.cpp +++ b/extern/shiny/Main/ScriptLoader.cpp @@ -14,9 +14,9 @@ namespace sh for ( boost::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir ) { boost::filesystem::path p(*dir); - if(p.extension() == c->m_fileEnding) + if(p.extension() == c->mFileEnding) { - c->m_currentFileName = (*dir).path().string(); + c->mCurrentFileName = (*dir).path().string(); std::ifstream in((*dir).path().string().c_str(), std::ios::binary); c->parseScript(in); } @@ -25,7 +25,7 @@ namespace sh ScriptLoader::ScriptLoader(const std::string& fileEnding) { - m_fileEnding = fileEnding; + mFileEnding = fileEnding; } ScriptLoader::~ScriptLoader() @@ -70,7 +70,7 @@ namespace sh { //Get first token _nextToken(stream); - if (tok == TOKEN_EOF) + if (mToken == TOKEN_EOF) { stream.close(); return; @@ -87,7 +87,7 @@ namespace sh //EOF token if (!stream.good()) { - tok = TOKEN_EOF; + mToken = TOKEN_EOF; return; } @@ -101,7 +101,7 @@ namespace sh if (!stream.good()) { - tok = TOKEN_EOF; + mToken = TOKEN_EOF; return; } @@ -115,21 +115,21 @@ namespace sh stream.unget(); - tok = TOKEN_NewLine; + mToken = TOKEN_NewLine; return; } //Open brace token else if (ch == '{') { - tok = TOKEN_OpenBrace; + mToken = TOKEN_OpenBrace; return; } //Close brace token else if (ch == '}') { - tok = TOKEN_CloseBrace; + mToken = TOKEN_CloseBrace; return; } @@ -139,8 +139,8 @@ namespace sh throw std::runtime_error("Parse Error: Invalid character, ConfigLoader::load()"); } - tokVal = ""; - tok = TOKEN_Text; + mTokenValue = ""; + mToken = TOKEN_Text; do { //Skip comments @@ -157,13 +157,13 @@ namespace sh ch = stream.get(); } while (ch != '\r' && ch != '\n' && !stream.eof()); - tok = TOKEN_NewLine; + mToken = TOKEN_NewLine; return; } } //Add valid char to tokVal - tokVal += (char)ch; + mTokenValue += (char)ch; //Next char ch = stream.get(); @@ -177,7 +177,7 @@ namespace sh void ScriptLoader::_skipNewLines(std::ifstream &stream) { - while (tok == TOKEN_NewLine) + while (mToken == TOKEN_NewLine) { _nextToken(stream); } @@ -189,7 +189,7 @@ namespace sh while (true) { - switch (tok) + switch (mToken) { //Node case TOKEN_Text: @@ -198,23 +198,23 @@ namespace sh ScriptNode *newNode; if (parent) { - newNode = parent->addChild(tokVal); + newNode = parent->addChild(mTokenValue); } else { - newNode = new ScriptNode(0, tokVal); + newNode = new ScriptNode(0, mTokenValue); } //Get values _nextToken(stream); std::string valueStr; int i=0; - while (tok == TOKEN_Text) + while (mToken == TOKEN_Text) { if (i == 0) - valueStr += tokVal; + valueStr += mTokenValue; else - valueStr += " " + tokVal; + valueStr += " " + mTokenValue; _nextToken(stream); ++i; } @@ -235,13 +235,13 @@ namespace sh _skipNewLines(stream); //Add any sub-nodes - if (tok == TOKEN_OpenBrace) + if (mToken == TOKEN_OpenBrace) { //Parse nodes _nextToken(stream); _parseNodes(stream, newNode); //Check for matching closing brace - if (tok != TOKEN_CloseBrace) + if (mToken != TOKEN_CloseBrace) { throw std::runtime_error("Parse Error: Expecting closing brace"); } @@ -249,7 +249,7 @@ namespace sh _skipNewLines(stream); } - newNode->m_fileName = m_currentFileName; + newNode->mFileName = mCurrentFileName; break; } @@ -276,16 +276,16 @@ namespace sh ScriptNode::ScriptNode(ScriptNode *parent, const std::string &name) { - m_name = name; - m_parent = parent; - _removeSelf = true; //For proper destruction - m_lastChildFound = -1; + mName = name; + mParent = parent; + mRemoveSelf = true; //For proper destruction + mLastChildFound = -1; //Add self to parent's child list (unless this is the root node being created) if (parent != NULL) { - m_parent->m_children.push_back(this); - _iter = --(m_parent->m_children.end()); + mParent->mChildren.push_back(this); + mIter = --(mParent->mChildren.end()); } } @@ -293,18 +293,18 @@ namespace sh { //Delete all children std::vector::iterator i; - for (i = m_children.begin(); i != m_children.end(); i++) + for (i = mChildren.begin(); i != mChildren.end(); i++) { ScriptNode *node = *i; - node->_removeSelf = false; + node->mRemoveSelf = false; delete node; } - m_children.clear(); + mChildren.clear(); //Remove self from parent's child list - if (_removeSelf && m_parent != NULL) + if (mRemoveSelf && mParent != NULL) { - m_parent->m_children.erase(_iter); + mParent->mChildren.erase(mIter); } } @@ -324,20 +324,20 @@ namespace sh ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive) { int indx, prevC, nextC; - int childCount = (int)m_children.size(); + int childCount = (int)mChildren.size(); - if (m_lastChildFound != -1) + if (mLastChildFound != -1) { //If possible, try checking the nodes neighboring the last successful search //(often nodes searched for in sequence, so this will boost search speeds). - prevC = m_lastChildFound-1; if (prevC < 0) prevC = 0; else if (prevC >= childCount) prevC = childCount-1; - nextC = m_lastChildFound+1; if (nextC < 0) nextC = 0; else if (nextC >= childCount) nextC = childCount-1; + prevC = mLastChildFound-1; if (prevC < 0) prevC = 0; else if (prevC >= childCount) prevC = childCount-1; + nextC = mLastChildFound+1; if (nextC < 0) nextC = 0; else if (nextC >= childCount) nextC = childCount-1; for (indx = prevC; indx <= nextC; ++indx) { - ScriptNode *node = m_children[indx]; - if (node->m_name == name) + ScriptNode *node = mChildren[indx]; + if (node->mName == name) { - m_lastChildFound = indx; + mLastChildFound = indx; return node; } } @@ -346,17 +346,17 @@ namespace sh //already searched area above. for (indx = nextC + 1; indx < childCount; ++indx) { - ScriptNode *node = m_children[indx]; - if (node->m_name == name) { - m_lastChildFound = indx; + ScriptNode *node = mChildren[indx]; + if (node->mName == name) { + mLastChildFound = indx; return node; } } for (indx = 0; indx < prevC; ++indx) { - ScriptNode *node = m_children[indx]; - if (node->m_name == name) { - m_lastChildFound = indx; + ScriptNode *node = mChildren[indx]; + if (node->mName == name) { + mLastChildFound = indx; return node; } } @@ -365,9 +365,9 @@ namespace sh { //Search for the node from start to finish for (indx = 0; indx < childCount; ++indx){ - ScriptNode *node = m_children[indx]; - if (node->m_name == name) { - m_lastChildFound = indx; + ScriptNode *node = mChildren[indx]; + if (node->mName == name) { + mLastChildFound = indx; return node; } } @@ -378,7 +378,7 @@ namespace sh { for (indx = 0; indx < childCount; ++indx) { - m_children[indx]->findChild(name, recursive); + mChildren[indx]->findChild(name, recursive); } } @@ -389,13 +389,13 @@ namespace sh void ScriptNode::setParent(ScriptNode *newParent) { //Remove self from current parent - m_parent->m_children.erase(_iter); + mParent->mChildren.erase(mIter); //Set new parent - m_parent = newParent; + mParent = newParent; //Add self to new parent - m_parent->m_children.push_back(this); - _iter = --(m_parent->m_children.end()); + mParent->mChildren.push_back(this); + mIter = --(mParent->mChildren.end()); } } diff --git a/extern/shiny/Main/ScriptLoader.hpp b/extern/shiny/Main/ScriptLoader.hpp index caf743bd2..89720fb5d 100644 --- a/extern/shiny/Main/ScriptLoader.hpp +++ b/extern/shiny/Main/ScriptLoader.hpp @@ -23,7 +23,7 @@ namespace sh ScriptLoader(const std::string& fileEnding); virtual ~ScriptLoader(); - std::string m_fileEnding; + std::string mFileEnding; // For a line like // entity animals/dog @@ -38,11 +38,11 @@ namespace sh void parseScript(std::ifstream &stream); - std::string m_currentFileName; + std::string mCurrentFileName; protected: - float m_LoadOrder; + float mLoadOrder; // like "*.object" std::map m_scriptList; @@ -56,8 +56,8 @@ namespace sh TOKEN_EOF }; - Token tok, lastTok; - std::string tokVal; + Token mToken, mLastToken; + std::string mTokenValue; void _parseNodes(std::ifstream &stream, ScriptNode *parent); void _nextToken(std::ifstream &stream); @@ -74,22 +74,22 @@ namespace sh inline void setName(const std::string &name) { - this->m_name = name; + this->mName = name; } inline std::string &getName() { - return m_name; + return mName; } inline void setValue(const std::string &value) { - m_value = value; + mValue = value; } inline std::string &getValue() { - return m_value; + return mValue; } ScriptNode *addChild(const std::string &name = "untitled", bool replaceExisting = false); @@ -97,36 +97,36 @@ namespace sh inline std::vector &getChildren() { - return m_children; + return mChildren; } inline ScriptNode *getChild(unsigned int index = 0) { - assert(index < m_children.size()); - return m_children[index]; + assert(index < mChildren.size()); + return mChildren[index]; } void setParent(ScriptNode *newParent); inline ScriptNode *getParent() { - return m_parent; + return mParent; } - std::string m_fileName; + std::string mFileName; private: - std::string m_name; - std::string m_value; - std::vector m_children; - ScriptNode *m_parent; + std::string mName; + std::string mValue; + std::vector mChildren; + ScriptNode *mParent; - int m_lastChildFound; //The last child node's index found with a call to findChild() + int mLastChildFound; //The last child node's index found with a call to findChild() - std::vector::iterator _iter; - bool _removeSelf; + std::vector::iterator mIter; + bool mRemoveSelf; }; } From d4a9236ae5ef0596dcbf53eaba64948abaa7692e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 8 Jan 2013 14:59:40 +0100 Subject: [PATCH 295/916] hocking up dialogue sub view to a widget mapper --- apps/opencs/view/world/dialoguesubview.cpp | 52 ++++++++++++++++++++++ apps/opencs/view/world/dialoguesubview.hpp | 3 ++ 2 files changed, 55 insertions(+) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 354223757..6138fd3f5 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -4,6 +4,10 @@ #include #include #include +#include +#include +#include +#include #include "../../model/world/columnbase.hpp" @@ -23,6 +27,9 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM int columns = model->columnCount(); + mWidgetMapper = new QDataWidgetMapper (this); + mWidgetMapper->setModel (model); + for (int i=0; iheaderData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags).toInt(); @@ -30,8 +37,53 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM if (flags & CSMWorld::ColumnBase::Flag_Dialogue) { layout->addWidget (new QLabel (model->headerData (i, Qt::Horizontal).toString()), i, 0); + + CSMWorld::ColumnBase::Display display = static_cast + (model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + QWidget *widget = 0; + + if (model->flags (model->index (0, i)) & Qt::ItemIsEditable) + { + switch (display) + { + case CSMWorld::ColumnBase::Display_String: + + layout->addWidget (widget = new QLineEdit, i, 1); + break; + + case CSMWorld::ColumnBase::Display_Integer: + + /// \todo configure widget properly (range) + layout->addWidget (widget = new QSpinBox, i, 1); + break; + + case CSMWorld::ColumnBase::Display_Float: + + /// \todo configure widget properly (range, format?) + layout->addWidget (widget = new QDoubleSpinBox, i, 1); + break; + } + } + else + { + switch (display) + { + case CSMWorld::ColumnBase::Display_String: + case CSMWorld::ColumnBase::Display_Integer: + case CSMWorld::ColumnBase::Display_Float: + + layout->addWidget (widget = new QLabel, i, 1); + break; + } + } + + if (widget) + mWidgetMapper->addMapping (widget, i); } } + + mWidgetMapper->toFirst(); /// \todo use the correct row instead } void CSVWorld::DialogueSubView::setEditLock (bool locked) diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index c57dab108..64715f5b7 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -3,6 +3,8 @@ #include "../doc/subview.hpp" +class QDataWidgetMapper; + namespace CSMDoc { class Document; @@ -12,6 +14,7 @@ namespace CSVWorld { class DialogueSubView : public CSVDoc::SubView { + QDataWidgetMapper *mWidgetMapper; public: From 39d27b87c92bc96b335692e92066eeddfd63b3c9 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 8 Jan 2013 09:14:56 -0800 Subject: [PATCH 296/916] fixed build error with Audiere coded enabled --- apps/openmw/mwsound/audiere_decoder.cpp | 5 +++-- apps/openmw/mwsound/audiere_decoder.hpp | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwsound/audiere_decoder.cpp b/apps/openmw/mwsound/audiere_decoder.cpp index 788d5ae40..3f3e3a62d 100644 --- a/apps/openmw/mwsound/audiere_decoder.cpp +++ b/apps/openmw/mwsound/audiere_decoder.cpp @@ -64,7 +64,8 @@ void Audiere_Decoder::open(const std::string &fname) close(); mSoundFile = audiere::FilePtr(new OgreFile(mResourceMgr.openResource(fname))); - mSoundSource = audiere::OpenSampleSource(file); + mSoundSource = audiere::OpenSampleSource(mSoundFile); + mSoundFileName = fname; int channels, srate; audiere::SampleFormat format; @@ -95,7 +96,7 @@ void Audiere_Decoder::close() std::string Audiere_Decoder::getName() { - return mSoundFile->getName(); + return mSoundFileName; } void Audiere_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) diff --git a/apps/openmw/mwsound/audiere_decoder.hpp b/apps/openmw/mwsound/audiere_decoder.hpp index 91c07ccac..f432c32ec 100644 --- a/apps/openmw/mwsound/audiere_decoder.hpp +++ b/apps/openmw/mwsound/audiere_decoder.hpp @@ -12,6 +12,7 @@ namespace MWSound { class Audiere_Decoder : public Sound_Decoder { + std::string mSoundFileName; audiere::FilePtr mSoundFile; audiere::SampleSourcePtr mSoundSource; int mSampleRate; From 135f0870f77304ffdeeea9c4e9a1ecb7e5967267 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 9 Jan 2013 02:16:17 +0000 Subject: [PATCH 297/916] in actionequip, was ignoring actor param, and always using player --- apps/openmw/mwworld/actionequip.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index d8c019644..3d922a816 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -15,8 +15,7 @@ namespace MWWorld void ActionEquip::executeImp (const Ptr& actor) { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(getTarget()).getEquipmentSlots(getTarget()); From 62a2ba1cc6cd9dbca65abf5fd174213c8cce6d32 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 9 Jan 2013 03:03:14 +0000 Subject: [PATCH 298/916] beast races cannot equip shoes/boots --- apps/openmw/mwworld/actionequip.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 3d922a816..f9e7658c8 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -2,6 +2,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "inventorystore.hpp" #include "player.hpp" @@ -31,11 +32,36 @@ namespace MWWorld } assert(it != invStore.end()); + + std::string npcRace = actor.get()->mBase->mRace; // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { + + // Beast races cannot equip shoes / boots + if(npcRace == "argonian" || npcRace == "khajiit") + { + if (*slot == MWWorld::InventoryStore::Slot_Boots) + { + // Only notify the player, not npcs + if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}", std::vector()); + } + + else // It's boots + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}", std::vector()); + } + } + } + + break; + } + // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) { From 719663d86eeedd77cce0f576126dd139356e97e7 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 8 Jan 2013 19:52:18 -0800 Subject: [PATCH 299/916] added option to override the activation distance The command line option '--activate-dist ' can be used to override the in game activation distance. --- apps/openmw/engine.cpp | 9 ++++++++- apps/openmw/engine.hpp | 4 ++++ apps/openmw/main.cpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 13 +++++++++++-- apps/openmw/mwworld/worldimp.hpp | 3 ++- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fcfaed47d..8c288a2ee 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -336,7 +336,8 @@ void OMW::Engine::go() // Create the world mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mCfgMgr.getCachePath(), mNewGame, &encoder, mFallbackMap)); + mResDir, mCfgMgr.getCachePath(), mNewGame, &encoder, mFallbackMap, + mActivationDistanceOverride)); //Load translation data mTranslationDataStorage.setEncoder(&encoder); @@ -509,3 +510,9 @@ void OMW::Engine::setStartupScript (const std::string& path) { mStartupScript = path; } + + +void OMW::Engine::setActivationDistanceOverride (int distance) +{ + mActivationDistanceOverride = distance; +} diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 00889197e..601cc7765 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -76,6 +76,7 @@ namespace OMW std::map mFallbackMap; bool mScriptConsoleMode; std::string mStartupScript; + int mActivationDistanceOverride; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; @@ -167,6 +168,9 @@ namespace OMW /// Set path for a script that is run on startup in the console. void setStartupScript (const std::string& path); + /// Override the game setting specified activation distance. + void setActivationDistanceOverride (int distance); + private: Files::ConfigurationManager& mCfgMgr; }; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 96dbf8987..d1a498610 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -149,6 +149,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("fallback", bpo::value()->default_value(FallbackMap(), "") ->multitoken()->composing(), "fallback values") + ("activate-dist", bpo::value ()->default_value (-1), "activation distance override"); + ; bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv) @@ -236,6 +238,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setFallbackValues(variables["fallback"].as().mMap); engine.setScriptConsoleMode (variables["script-console"].as()); engine.setStartupScript (variables["script-run"].as()); + engine.setActivationDistanceOverride (variables["activate-dist"].as()); return true; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 739d0daab..766fdafa8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -170,10 +170,10 @@ namespace MWWorld World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - ToUTF8::Utf8Encoder* encoder, std::map fallbackMap) + ToUTF8::Utf8Encoder* encoder, std::map fallbackMap, int mActivationDistanceOverride) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), - mNumFacing(0) + mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -575,16 +575,25 @@ namespace MWWorld float World::getMaxActivationDistance () { + if (mActivationDistanceOverride >= 0) + return mActivationDistanceOverride; + return (std::max) (getNpcActivationDistance (), getObjectActivationDistance ()); } float World::getNpcActivationDistance () { + if (mActivationDistanceOverride >= 0) + return mActivationDistanceOverride; + return getStore().get().find ("iMaxActivateDist")->getInt()*5/4; } float World::getObjectActivationDistance () { + if (mActivationDistanceOverride >= 0) + return mActivationDistanceOverride; + return getStore().get().find ("iMaxActivateDist")->getInt(); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a1ba6fcde..6f8bacf72 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -71,6 +71,7 @@ namespace MWWorld Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cellStore); + int mActivationDistanceOverride; std::string mFacedHandle; float mFacedDistance; Ptr mFaced1; @@ -109,7 +110,7 @@ namespace MWWorld World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - ToUTF8::Utf8Encoder* encoder, std::map fallbackMap); + ToUTF8::Utf8Encoder* encoder, std::map fallbackMap, int mActivationDistanceOverride); virtual ~World(); From 857bb42297f92d2fa3f911cfb9e7e2c0d1660558 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 01:44:15 -0400 Subject: [PATCH 300/916] Create a separate scenemanager for each CharacterPreview instance --- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/race.cpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 13 ++++++++++--- apps/openmw/mwrender/characterpreview.hpp | 4 ++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ffb6c5282..5390f1602 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -67,7 +67,7 @@ namespace MWGui setCoord(0, 342, 498, 258); - MWBase::Environment::get().getWorld ()->setupExternalRendering (mPreview); + mPreview.setup(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); openContainer(player); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index d2714fb51..df6c99340 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -106,7 +106,7 @@ void RaceDialog::open() updateSpellPowers(); mPreview = new MWRender::RaceSelectionPreview(); - MWBase::Environment::get().getWorld ()->setupExternalRendering (*mPreview); + mPreview->setup(); mPreview->update (0); const ESM::NPC proto = mPreview->getPrototype(); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 0a11dc281..b034e098b 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -35,13 +36,18 @@ namespace MWRender } - void CharacterPreview::setup (Ogre::SceneManager *sceneManager) + void CharacterPreview::setup () { - mSceneMgr = sceneManager; + mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); mCamera = mSceneMgr->createCamera (mName); mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); - mNode = static_cast(mSceneMgr->getRootSceneNode()->getChild("mwRoot"))->createChildSceneNode (); + Ogre::SceneNode* renderRoot = mSceneMgr->getRootSceneNode()->createChildSceneNode("renderRoot"); + + //we do this with mwRoot in renderingManager, do it here too. + renderRoot->pitch(Ogre::Degree(-90)); + + mNode = renderRoot->createChildSceneNode(); mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), RV_PlayerPreview); @@ -79,6 +85,7 @@ namespace MWRender //Ogre::TextureManager::getSingleton().remove(mName); mSceneMgr->destroyCamera (mName); delete mAnimation; + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); } void CharacterPreview::rebuild() diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 18362d1db..d07a03be7 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -23,14 +23,14 @@ namespace MWRender class NpcAnimation; - class CharacterPreview : public ExternalRendering + class CharacterPreview { public: CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt); virtual ~CharacterPreview(); - virtual void setup (Ogre::SceneManager *sceneManager); + virtual void setup (); virtual void onSetup(); virtual void rebuild(); From 43cd88a24eece09e6f83e586fd3248f4a211636a Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 4 Jan 2013 00:02:57 -0800 Subject: [PATCH 301/916] include members of BSAArchives in Ogres resource indices --- components/bsa/bsa_archive.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 8380b0838..671744a77 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -249,6 +249,13 @@ public: //std::cout << "find(" << pattern << ", " << recursive // << ", " << dirs << ")\n"; StringVectorPtr ptr = StringVectorPtr(new StringVector()); + + BSAFile::FileList const & files = arc.getList (); + + if (pattern == "*") + for (BSAFile::FileList::const_iterator i = files.begin (); i != files.end (); ++i) + ptr->push_back (i->name); + return ptr; } From 67491f6c49b37f02ce376053195c73c9929ec76b Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 4 Jan 2013 09:32:42 -0800 Subject: [PATCH 302/916] reworked DirArchive to improve performance Replaced old file index with a simple map. The map works by storing the file's relative path with path seperators normalized, and in lower case if not in strict mode. Incoming searches are normalized in the same way then the name is searched in the map. The value in the map is the original full path to the file which is then used to created a ConstrainedDataStream. In addition to changing the index, the commonly used Archive methods are implemented so that they don't fall back on the default FileSystemArchive implementations. --- components/bsa/bsa_archive.cpp | 212 +++++++++++++++++---------------- 1 file changed, 112 insertions(+), 100 deletions(-) diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 671744a77..b067c5290 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -29,6 +29,8 @@ #include #include "bsa_file.hpp" +#include "../files/constrainedfiledatastream.hpp" + namespace { @@ -60,104 +62,64 @@ public: static bool fsstrict = false; /// An OGRE Archive wrapping a BSAFile archive -class DirArchive: public Ogre::FileSystemArchive +class DirArchive: public Ogre::Archive { - boost::filesystem::path currentdir; - std::map, ciLessBoost> m; - unsigned int cutoff; + typedef std::map index; - bool findFile(const String& filename, std::string& copy) const + index mIndex; + + static char strict_normalize_char(char ch) { - copy = filename; - std::replace(copy.begin(), copy.end(), '\\', '/'); - - if(copy.at(0) == '/') - copy.erase(0, 1); - - if(fsstrict == true) - return true; - - std::string folder; - //int delimiter = 0; - size_t lastSlash = copy.rfind('/'); - if (lastSlash != std::string::npos) - { - folder = copy.substr(0, lastSlash); - //delimiter = lastSlash+1; - } - - std::vector current; - { - std::map,ciLessBoost>::const_iterator found = m.find(folder); - - if (found == m.end()) - { - return false; - } - else - current = found->second; - } - - std::vector::iterator find = std::lower_bound(current.begin(), current.end(), copy, ciLessBoost()); - if (find != current.end() && !ciLessBoost()(copy, current.front())) - { - if (!boost::iequals(copy, *find)) - if ((find = std::find_if(current.begin(), current.end(), pathComparer(copy))) == current.end()) //\todo Check if this line is actually needed - return false; - - copy = *find; - return true; - } - - return false; + return ch == '\\' ? '/' : ch; } - public: + static char nonstrict_normalize_char(char ch) + { + return ch == '\\' ? '/' : std::tolower (ch); + } + + static std::string normalize_path (std::string::const_iterator begin, std::string::const_iterator end) + { + std::string normalized; + normalized.reserve (end-begin); + char (*normalize_char) (char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char; + std::transform (begin, end, std::back_inserter (normalized), normalize_char); + return normalized; + } + + index::const_iterator lookup_filename (std::string const & filename) const + { + std::string normalized = normalize_path (filename.begin (), filename.end ()); + + return mIndex.find (normalized); + } + +public: DirArchive(const String& name) - : FileSystemArchive(name, "Dir"), currentdir (name) + : Archive(name, "Dir") { - mType = "Dir"; - std::string s = name; - cutoff = s.size() + 1; - if(fsstrict == false) - populateMap(currentdir); + typedef boost::filesystem::recursive_directory_iterator directory_iterator; - } - void populateMap(boost::filesystem::path d){ - //need to cut off first - boost::filesystem::directory_iterator dir_iter(d), dir_end; - std::vector filesind; - for(;dir_iter != dir_end; dir_iter++) - { - if(boost::filesystem::is_directory(*dir_iter)) - populateMap(*dir_iter); - else + directory_iterator end; + + size_t prefix = name.size (); + + if (name.size () > 0 && name [prefix - 1] != '\\' && name [prefix - 1] != '/') + ++prefix; + + for (directory_iterator i (name); i != end; ++i) { - std::string s = dir_iter->path().string(); - std::replace(s.begin(), s.end(), '\\', '/'); + if(boost::filesystem::is_directory (*i)) + continue; - std::string small; - if(cutoff < s.size()) - small = s.substr(cutoff, s.size() - cutoff); - else - small = s.substr(cutoff - 1, s.size() - cutoff); + std::string proper = i->path ().string (); - filesind.push_back(small); + std::string searchable = normalize_path (proper.begin () + prefix, proper.end ()); + + mIndex.insert (std::make_pair (std::move (searchable), std::move (proper))); } } - std::sort(filesind.begin(), filesind.end(), ciLessBoost()); - - std::string small; - std::string original = d.string(); - std::replace(original.begin(), original.end(), '\\', '/'); - if(cutoff < original.size()) - small = original.substr(cutoff, original.size() - cutoff); - else - small = original.substr(cutoff - 1, original.size() - cutoff); - - m[small] = filesind; - } bool isCaseSensitive() const { return fsstrict; } @@ -165,26 +127,76 @@ class DirArchive: public Ogre::FileSystemArchive void load() {} void unload() {} - bool exists(const String& filename) { - std::string copy; - - if (findFile(filename, copy)) - return FileSystemArchive::exists(copy); - - return false; - } - DataStreamPtr open(const String& filename, bool readonly = true) const - { - std::string copy; + { + index::const_iterator i = lookup_filename (filename); - if (findFile(filename, copy)) - return FileSystemArchive::open(copy, readonly); + if (i == mIndex.end ()) + { + std::ostringstream os; + os << "The file '" << filename << "' could not be found."; + throw std::runtime_error (os.str ()); + } - DataStreamPtr p; - return p; - } + return openConstrainedFileDataStream (i->second.c_str ()); + } + StringVectorPtr list(bool recursive = true, bool dirs = false) + { + StringVectorPtr ptr = StringVectorPtr(new StringVector()); + std::cout << "DirArchive<" << getName () << ">::list" << std::endl; + return ptr; + } + + FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) + { + FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); + std::cout << "DirArchive<" << getName () << ">::listFileInfo" << std::endl; + return ptr; + } + + StringVectorPtr find(const String& pattern, bool recursive = true, + bool dirs = false) + { + StringVectorPtr ptr = StringVectorPtr(new StringVector()); + + if (pattern == "*") + for (index::const_iterator i = mIndex.begin (); i != mIndex.end (); ++i) + ptr->push_back (i->first); + + return ptr; + } + + bool exists(const String& filename) + { + return lookup_filename (filename) != mIndex.end (); + } + + time_t getModifiedTime(const String&) { return 0; } + + FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, + bool dirs = false) const + { + FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); + + index::const_iterator i = lookup_filename (pattern); + + if (i != mIndex.end ()) + { + FileInfo fi; + + std::size_t npos = i->first.rfind ('/'); + + fi.archive = this; + fi.filename = npos != -1 ? i->first.substr (npos) : i->first; + fi.path = npos != -1 ? i->first.substr (0, npos) : ""; + fi.compressedSize = fi.uncompressedSize = 0; + + ptr->push_back(fi); + } + + return ptr; + } }; class BSAArchive : public Archive From e44729cd43a98ee35bea3b123f3e021cdc6dceee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 00:17:42 -0800 Subject: [PATCH 303/916] Make the text keys lower-case when extracting them I think it's safe to assume all text keys are treated in a case-insensitive manner. So far the only known NiTextKeyExtraData records are for animation keys, which effectively are. --- apps/openmw/mwrender/animation.cpp | 5 ----- components/nifogre/ogre_nif_loader.cpp | 13 +++++++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6da3ad583..4e33873d3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -75,11 +75,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(mTextKeys.size() > 0) { - NifOgre::TextKeyMap::iterator keyiter; - for(keyiter = mTextKeys.begin();keyiter != mTextKeys.end();keyiter++) - std::transform(keyiter->second.begin(), keyiter->second.end(), - keyiter->second.begin(), ::tolower); - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); while(as.hasMoreElements()) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e71c57efa..803496bf9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -286,13 +286,18 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) std::string::size_type pos = 0; while(pos < str.length()) { - while(pos < str.length() && ::isspace(str[pos])) + if(::isspace(str[pos])) + { pos++; - if(pos >= str.length()) - break; + continue; + } std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - textkeys.insert(std::make_pair(tk->list[i].time, str.substr(pos, nextpos-pos))); + std::string result; + result.reserve(str.length()); + std::transform(str.begin()+pos, str.begin()+std::min(str.length(), nextpos), + std::back_inserter(result), ::tolower); + textkeys.insert(std::make_pair(tk->list[i].time, result)); pos = nextpos; } From bb98542c5a5d16c40713e1a0f847d7735a8c7abe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 01:40:38 -0800 Subject: [PATCH 304/916] Build separate animations for each group --- apps/openmw/mwrender/animation.cpp | 55 ++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 4 +- components/nifogre/ogre_nif_loader.cpp | 38 ++++++++++++++++++ 3 files changed, 70 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4e33873d3..4448360bd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,7 +23,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mTime(0.0f) , mCurGroup(mTextKeys.end()) , mNextGroup(mTextKeys.end()) - , mAnimState(NULL) , mSkipFrame(false) { } @@ -80,10 +79,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(as.hasMoreElements()) { Ogre::AnimationState *state = as.getNext(); - state->setEnabled(true); + state->setEnabled(false); state->setLoop(false); - if(!mAnimState) - mAnimState = state; } } } @@ -92,12 +89,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model void Animation::updatePosition(float time) { - mAnimState->setTimePosition(time); + mCurGroup.mAnimState->setTimePosition(time); if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; /* Translate the accumulation root back to compensate for the move. */ @@ -118,10 +115,10 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { - mAnimState->setTimePosition(time); + mCurGroup.mAnimState->setTimePosition(time); if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } @@ -162,24 +159,27 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim void Animation::playGroup(std::string groupname, int mode, int loops) { - if(mTextKeys.size() == 0) - { - std::cerr<< "Trying to animate an unanimate object" <getAnimationState(groupname); + times.mLoops = loops; + + if(groupname == "all") + { + times.mStart = times.mLoopStart = mTextKeys.begin(); + times.mLoopStop = times.mStop = mTextKeys.end(); + times.mLoopStop--; times.mStop--; + } + else if(!findGroupTimes(groupname, ×)) + throw std::runtime_error("Failed to find animation group "+groupname); } - else if(!findGroupTimes(groupname, ×)) - { - std::cerr<< "Failed to find animation group "<setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(mTextKeys.end()); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; + mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); } } @@ -201,7 +204,7 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mAnimState && !mSkipFrame) + if(mCurGroup.mAnimState && !mSkipFrame) { mTime += timepassed; recheck: @@ -221,9 +224,11 @@ void Animation::runAnimation(float timepassed) { updatePosition(mCurGroup.mStop->first); mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; - resetPosition(mNextGroup.mStart->first); + mCurGroup.mAnimState->setEnabled(false); mCurGroup = mNextGroup; mNextGroup = GroupTimes(mTextKeys.end()); + mCurGroup.mAnimState->setEnabled(true); + resetPosition(mNextGroup.mStart->first); goto recheck; } mTime = mCurGroup.mStop->first; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 44a2eaf3e..e84ebb358 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,11 +16,12 @@ class Animation NifOgre::TextKeyMap::const_iterator mLoopStart; NifOgre::TextKeyMap::const_iterator mLoopStop; + Ogre::AnimationState *mAnimState; size_t mLoops; GroupTimes(NifOgre::TextKeyMap::const_iterator iter) : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), - mLoops(0) + mAnimState(NULL), mLoops(0) { } }; @@ -38,7 +39,6 @@ protected: float mTime; GroupTimes mCurGroup; GroupTimes mNextGroup; - Ogre::AnimationState *mAnimState; bool mSkipFrame; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 803496bf9..c4846cdfd 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -410,7 +410,45 @@ void loadResource(Ogre::Resource *resource) return; } + TextKeyMap textkeys; + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.peekNext(); + const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(sTextKeyExtraDataID); + if(!data.isEmpty()) + { + textkeys = Ogre::any_cast(data); + break; + } + boneiter.moveNext(); + } + buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); + + std::string currentgroup; + TextKeyMap::const_iterator keyiter = textkeys.begin(); + for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) + { + std::string::size_type sep = keyiter->second.find(':'); + if(sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) + continue; + currentgroup = keyiter->second.substr(0, sep); + + if(skel->hasAnimation(currentgroup)) + continue; + + TextKeyMap::const_reverse_iterator lastkeyiter = textkeys.rbegin(); + while(lastkeyiter->first > keyiter->first) + { + if(lastkeyiter->second.find(':') == currentgroup.length() && + lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) + break; + lastkeyiter++; + } + + buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + } } bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) From 4054934f1699affd865977148f45b4137d8e7b16 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 02:51:25 -0800 Subject: [PATCH 305/916] Store text keys for each animation --- components/nifogre/ogre_nif_loader.cpp | 29 +++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c4846cdfd..1b0d3168c 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -431,23 +431,29 @@ void loadResource(Ogre::Resource *resource) for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) { std::string::size_type sep = keyiter->second.find(':'); - if(sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) + if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || + (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) continue; currentgroup = keyiter->second.substr(0, sep); if(skel->hasAnimation(currentgroup)) continue; - TextKeyMap::const_reverse_iterator lastkeyiter = textkeys.rbegin(); - while(lastkeyiter->first > keyiter->first) + TextKeyMap::const_iterator lastkeyiter = textkeys.end(); + while((--lastkeyiter)->first > keyiter->first) { if(lastkeyiter->second.find(':') == currentgroup.length() && lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) break; - lastkeyiter++; } buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + + TextKeyMap groupkeys; + groupkeys.insert(keyiter, ++lastkeyiter); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); + bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } @@ -459,12 +465,7 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif if(node->boneTrafo != NULL) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(name); - if(skel.isNull()) - { - NIFSkeletonLoader *loader = &sLoaders[name]; - skel = skelMgr.create(name, group, true, loader); - } + skelMgr.create(name, group, true, &sLoaders[name]); return true; } @@ -1129,8 +1130,12 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam return meshes; } - NIFSkeletonLoader skelldr; - bool hasSkel = skelldr.createSkeleton(name, group, node); + bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); + if(!hasSkel) + { + NIFSkeletonLoader skelldr; + hasSkel = skelldr.createSkeleton(name, group, node); + } NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); meshldr.createMeshes(node, meshes); From d1e51ebf426b47e6c1d4e35775ca66407ef474fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 9 Jan 2013 12:25:45 +0100 Subject: [PATCH 306/916] silenced some warnings --- components/bsa/bsa_archive.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index b067c5290..011b81351 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -188,8 +188,8 @@ public: std::size_t npos = i->first.rfind ('/'); fi.archive = this; - fi.filename = npos != -1 ? i->first.substr (npos) : i->first; - fi.path = npos != -1 ? i->first.substr (0, npos) : ""; + fi.filename = npos != std::string::npos ? i->first.substr (npos) : i->first; + fi.path = npos != std::string::npos ? i->first.substr (0, npos) : ""; fi.compressedSize = fi.uncompressedSize = 0; ptr->push_back(fi); From 1e38e381a4344210872ea8f86d5347c1ac5b3fa0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 03:30:55 -0800 Subject: [PATCH 307/916] Use text keys for each animation --- apps/openmw/mwrender/animation.cpp | 76 ++++++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 7 ++- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4448360bd..59dcd451b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,8 +21,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mTime(0.0f) - , mCurGroup(mTextKeys.end()) - , mNextGroup(mTextKeys.end()) , mSkipFrame(false) { } @@ -48,19 +46,27 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) + { + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); + } + Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); - Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); - while(iter.hasMoreElements()) + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) { - Ogre::Bone *bone = iter.getNext(); + Ogre::Bone *bone = boneiter.peekNext(); const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); if(!data.isEmpty()) { - mTextKeys = Ogre::any_cast(data); - mNextGroup = mCurGroup = GroupTimes(mTextKeys.begin()); + mTextKeys["all"] = Ogre::any_cast(data); mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); @@ -70,17 +76,19 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mLastPosition = mStartPosition; break; } + boneiter.moveNext(); } - if(mTextKeys.size() > 0) + if(boneiter.hasMoreElements()) { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); - while(as.hasMoreElements()) + asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) { - Ogre::AnimationState *state = as.getNext(); - state->setEnabled(false); - state->setLoop(false); + Ogre::AnimationState *state = asiter.getNext(); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+"@"+state->getAnimationName()); + if(!data.isEmpty()) + mTextKeys[state->getAnimationName()] = Ogre::any_cast(data); } } } @@ -127,13 +135,28 @@ void Animation::resetPosition(float time) bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { + const NifOgre::TextKeyMap &textkeys = mTextKeys[groupname]; + if(textkeys.size() == 0) + return false; + + if(groupname == "all") + { + times->mStart = times->mLoopStart = textkeys.begin(); + times->mLoopStop = times->mStop = textkeys.end(); + times->mLoopStop--; times->mStop--; + return true; + } + const std::string start = groupname+": start"; const std::string startloop = groupname+": loop start"; const std::string stop = groupname+": stop"; const std::string stoploop = groupname+": loop stop"; + times->mStart = times->mLoopStart = + times->mStop = times->mLoopStop = textkeys.end(); + NifOgre::TextKeyMap::const_iterator iter; - for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) + for(iter = textkeys.begin();iter != textkeys.end();iter++) { if(start == iter->second) { @@ -147,9 +170,9 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim else if(stop == iter->second) { times->mStop = iter; - if(times->mLoopStop == mTextKeys.end()) + if(times->mLoopStop == textkeys.end()) times->mLoopStop = iter; - return (times->mStart != mTextKeys.end()); + return (times->mStart != textkeys.end()); } } @@ -159,23 +182,14 @@ bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTim void Animation::playGroup(std::string groupname, int mode, int loops) { - GroupTimes times(mTextKeys.end()); + GroupTimes times; try { - if(mTextKeys.size() == 0) - throw std::runtime_error("Trying to animate an unanimate object"); - std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); times.mLoops = loops; - if(groupname == "all") - { - times.mStart = times.mLoopStart = mTextKeys.begin(); - times.mLoopStop = times.mStop = mTextKeys.end(); - times.mLoopStop--; times.mStop--; - } - else if(!findGroupTimes(groupname, ×)) + if(!findGroupTimes(groupname, ×)) throw std::runtime_error("Failed to find animation group "+groupname); } catch(std::exception &e) { @@ -190,7 +204,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) if(mCurGroup.mAnimState) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; - mNextGroup = GroupTimes(mTextKeys.end()); + mNextGroup = GroupTimes(); mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); @@ -226,9 +240,9 @@ void Animation::runAnimation(float timepassed) mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; mCurGroup.mAnimState->setEnabled(false); mCurGroup = mNextGroup; - mNextGroup = GroupTimes(mTextKeys.end()); + mNextGroup = GroupTimes(); mCurGroup.mAnimState->setEnabled(true); - resetPosition(mNextGroup.mStart->first); + resetPosition(mCurGroup.mStart->first); goto recheck; } mTime = mCurGroup.mStop->first; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index e84ebb358..859d2b989 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -19,9 +19,8 @@ class Animation Ogre::AnimationState *mAnimState; size_t mLoops; - GroupTimes(NifOgre::TextKeyMap::const_iterator iter) - : mStart(iter), mStop(iter), mLoopStart(iter), mLoopStop(iter), - mAnimState(NULL), mLoops(0) + GroupTimes() + : mAnimState(NULL), mLoops(0) { } }; @@ -30,7 +29,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; - NifOgre::TextKeyMap mTextKeys; + std::map mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mStartPosition; From 465fd9c8afbce80590fd8b48d244cd6bbd344e52 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 04:10:02 -0800 Subject: [PATCH 308/916] Offset animation times to start at 0 --- components/nifogre/ogre_nif_loader.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1b0d3168c..b065e5fd3 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -164,7 +164,7 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { - Ogre::Animation *anim = skel->createAnimation(name, stopTime); + Ogre::Animation *anim = skel->createAnimation(name, stopTime-startTime); for(size_t i = 0;i < ctrls.size();i++) { @@ -246,7 +246,7 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const } Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); + kframe = nodetrack->createNodeKeyFrame(curtime-startTime); if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) kframe->setRotation(curquat); else @@ -450,8 +450,12 @@ void loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + TextKeyMap::const_iterator insiter = keyiter; TextKeyMap groupkeys; - groupkeys.insert(keyiter, ++lastkeyiter); + do { + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); + } while(insiter++ != lastkeyiter); + Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } From 015bb0bf1f309fcff7b61a4e23cdb8484fb97c45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 04:30:32 -0800 Subject: [PATCH 309/916] Use the calculated max time for the "all" animation --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b065e5fd3..b37b989c7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -424,7 +424,7 @@ void loadResource(Ogre::Resource *resource) boneiter.moveNext(); } - buildAnimation(skel, "all", ctrls, targets, 0.0f, std::numeric_limits::max()); + buildAnimation(skel, "all", ctrls, targets, 0.0f, maxtime); std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); From a9bcbfd8d364210c75120e36f258792d45e90edd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 05:11:32 -0800 Subject: [PATCH 310/916] Use Node::_getFullTransform instead of building the matrix manually --- components/nifogre/ogre_nif_loader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b37b989c7..08a5855ed 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -803,12 +803,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader for(size_t b = 0;b < bones.length();b++) { Ogre::Bone *bone = skel->getBone(bones[b]->name); - Ogre::Matrix4 mat, mat2; + Ogre::Matrix4 mat; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat2.makeTransform(bone->_getDerivedPosition(), bone->_getDerivedScale(), - bone->_getDerivedOrientation()); - mat = mat2 * mat; + mat = bone->_getFullTransform() * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) From b035a5aa4a3cb4be7df7a5ac7befc25a10f1202b Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 9 Jan 2013 13:18:05 +0000 Subject: [PATCH 311/916] beast races cannot equip anything they oughtn't to be able to equip --- apps/openmw/mwworld/actionequip.cpp | 49 +++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index f9e7658c8..0b4ca95ed 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,23 +43,46 @@ namespace MWWorld // Beast races cannot equip shoes / boots if(npcRace == "argonian" || npcRace == "khajiit") { - if (*slot == MWWorld::InventoryStore::Slot_Boots) - { - // Only notify the player, not npcs - if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { - if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}", std::vector()); - } + if(*slot == MWWorld::InventoryStore::Slot_Helmet){ + std::vector parts; - else // It's boots - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}", std::vector()); - } + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + + bool allow = true; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PartReferenceType::PRT_Head) + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector()); + allow = false; + break; } + } + + if(!allow) + break; + } + + if (*slot == MWWorld::InventoryStore::Slot_Boots) + { + // Only notify the player, not npcs + if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}", std::vector()); + } + + else // It's boots + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}", std::vector()); + } + } + break; } - break; } // if all slots are occupied, replace the last slot From 375961fe5ea4c516878f08e11fbe492d3aadf6b6 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 9 Jan 2013 13:27:12 +0000 Subject: [PATCH 312/916] small fix --- apps/openmw/mwworld/actionequip.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 0b4ca95ed..60260a812 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -40,7 +40,7 @@ namespace MWWorld slot!=slots.first.end(); ++slot) { - // Beast races cannot equip shoes / boots + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) if(npcRace == "argonian" || npcRace == "khajiit") { if(*slot == MWWorld::InventoryStore::Slot_Helmet){ @@ -56,7 +56,9 @@ namespace MWWorld { if((*itr).mPart == ESM::PartReferenceType::PRT_Head) { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector()); + if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector()); + allow = false; break; } From 3e41a1118a51bb38682a38b01ac56bf7473d7c27 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 9 Jan 2013 15:14:17 +0100 Subject: [PATCH 313/916] GetDisposition: return calculated disposition instead of base disposition --- apps/openmw/mwscript/statsextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 9e630aedf..fc138d351 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -674,7 +674,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - runtime.push (MWWorld::Class::get (ptr).getNpcStats (ptr).getBaseDisposition()); + runtime.push (MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr)); } }; From 4b7cc1372f4d2500effee6fb3482a1e8fc56b9f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 06:32:31 -0800 Subject: [PATCH 314/916] Some cleanup --- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 08a5855ed..cfc0d8397 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1008,7 +1008,7 @@ public: virtual void loadResource(Ogre::Resource *resource) { Ogre::Mesh *mesh = dynamic_cast(resource); - assert(mesh && "Attempting to load a mesh into a non-mesh resource!"); + OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); if(!mShapeName.length()) { @@ -1116,7 +1116,7 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam Nif::NIFFile nif(name); if (nif.numRecords() < 1) { - nif.warn("Found no records in NIF."); + nif.warn("Found no NIF records in "+name+"."); return meshes; } @@ -1127,8 +1127,8 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First record in file was not a node, but a "+ - r->recName+". Skipping file."); + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); return meshes; } @@ -1204,16 +1204,13 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = bonename; - std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower); + std::string filter; filter.resize(bonename.length()); + std::transform(bonename.begin(), bonename.end(), filter.begin(), ::tolower); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - std::transform(meshes[i].mTargetNode.begin(), meshes[i].mTargetNode.end(), - meshes[i].mTargetNode.begin(), ::tolower); - if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) { sceneMgr->destroyEntity(ent); From 625a538f03e9d88adbd3431bb7c8810bc3d6c564 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 07:43:10 -0800 Subject: [PATCH 315/916] Combine part selection into a single loop --- apps/openmw/mwrender/npcanimation.cpp | 239 +++++++++++--------------- 1 file changed, 96 insertions(+), 143 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5682a86cc..e4eea6c71 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -133,161 +133,114 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor void NpcAnimation::updateParts() { - bool apparelChanged = false; - static const struct { - MWWorld::ContainerStoreIterator NpcAnimation::*iter; + int numRemoveParts; // Max: 1 + ESM::PartReferenceType removeParts[1]; + + MWWorld::ContainerStoreIterator NpcAnimation::*part; int slot; + + int numReserveParts; // Max: 12 + ESM::PartReferenceType reserveParts[12]; } slotlist[] = { - { &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe }, - { &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, - { &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet }, - { &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, - { &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves }, - { &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, - { &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, - { &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots }, - { &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, - { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, - { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt }, - { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants }, + { 0, { }, + &NpcAnimation::mRobe, MWWorld::InventoryStore::Slot_Robe, + 12, { ESM::PRT_Groin, ESM::PRT_Skirt, ESM::PRT_RLeg, ESM::PRT_LLeg, + ESM::PRT_RUpperarm, ESM::PRT_LUpperarm, ESM::PRT_RKnee, ESM::PRT_LKnee, + ESM::PRT_RForearm, ESM::PRT_LForearm, ESM::PRT_RPauldron, ESM::PRT_LPauldron } + }, + + { 0, { }, + &NpcAnimation::mSkirtIter, MWWorld::InventoryStore::Slot_Skirt, + 3, { ESM::PRT_Groin, ESM::PRT_RLeg, ESM::PRT_LLeg } + }, + + { 1, { ESM::PRT_Hair }, + &NpcAnimation::mHelmet, MWWorld::InventoryStore::Slot_Helmet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mCuirass, MWWorld::InventoryStore::Slot_Cuirass, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGreaves, MWWorld::InventoryStore::Slot_Greaves, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mBoots, MWWorld::InventoryStore::Slot_Boots, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, + 0, { } + }, + + { 0, { }, + &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, + 0, { } + }, }; - for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) + static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + + for(size_t i = 0;i < slotlistsize;i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(this->*slotlist[i].iter != iter) - { - this->*slotlist[i].iter = iter; - removePartGroup(slotlist[i].slot); - apparelChanged = true; - } - } + if(this->*slotlist[i].part == iter) + continue; - if(apparelChanged) - { - if(mRobe != mInv.end()) - { - MWWorld::Ptr ptr = *mRobe; + this->*slotlist[i].part = iter; + removePartGroup(slotlist[i].slot); - const ESM::Clothing *clothes = (ptr.get())->mBase; + if(this->*slotlist[i].part == mInv.end()) + continue; + + for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++) + removeIndividualPart(slotlist[i].removeParts[rem]); + + int prio = 1; + MWWorld::ContainerStoreIterator &store = this->*slotlist[i].part; + if(store->getTypeName() == typeid(ESM::Clothing).name()) + { + prio = ((slotlist[i].numReserveParts+1)<<1) + 0; + const ESM::Clothing *clothes = store->get()->mBase; std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); - reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); + addPartGroup(slotlist[i].slot, prio, parts); } - if(mSkirtIter != mInv.end()) + else if(store->getTypeName() == typeid(ESM::Armor).name()) { - MWWorld::Ptr ptr = *mSkirtIter; - - const ESM::Clothing *clothes = (ptr.get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts); - reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4); - reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Skirt, 4); - reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); + prio = ((slotlist[i].numReserveParts+1)<<1) + 1; + const ESM::Armor *armor = store->get()->mBase; + std::vector parts = armor->mParts.mParts; + addPartGroup(slotlist[i].slot, prio, parts); } - if(mHelmet != mInv.end()) - { - removeIndividualPart(ESM::PRT_Hair); - const ESM::Armor *armor = (mHelmet->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); - } - if(mCuirass != mInv.end()) - { - const ESM::Armor *armor = (mCuirass->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); - } - if(mGreaves != mInv.end()) - { - const ESM::Armor *armor = (mGreaves->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); - } - - if(mPauldronL != mInv.end()) - { - const ESM::Armor *armor = (mPauldronL->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); - } - if(mPauldronR != mInv.end()) - { - const ESM::Armor *armor = (mPauldronR->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); - } - if(mBoots != mInv.end()) - { - if(mBoots->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mBoots->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); - } - else if(mBoots->getTypeName() == typeid(ESM::Armor).name()) - { - const ESM::Armor *armor = (mBoots->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); - } - } - if(mGloveL != mInv.end()) - { - if(mGloveL->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mGloveL->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (mGloveL->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); - } - } - if(mGloveR != mInv.end()) - { - if(mGloveR->getTypeName() == typeid(ESM::Clothing).name()) - { - const ESM::Clothing *clothes = (mGloveR->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (mGloveR->get())->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); - } - - } - - if(mShirt != mInv.end()) - { - const ESM::Clothing *clothes = (mShirt->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); - } - if(mPants != mInv.end()) - { - const ESM::Clothing *clothes = (mPants->get())->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); - } + for(int res = 0;res < slotlist[i].numReserveParts;res++) + reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio); } if(mPartPriorities[ESM::PRT_Head] < 1) @@ -455,7 +408,7 @@ void NpcAnimation::addPartGroup(int group, int priority, std::vectormModel); + addOrReplaceIndividualPart(part.mPart, group, priority, "meshes\\"+bodypart->mModel); else reserveIndividualPart(part.mPart, group, priority); } From 9fedaf18d6d724156910e23be9325882c79787a4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 07:55:55 -0800 Subject: [PATCH 316/916] Make some methods private --- apps/openmw/mwrender/npcanimation.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 090366a23..1a121be07 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -83,12 +83,7 @@ private: int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[sPartListSize]; -public: - NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& inv, int visibilityFlags); - virtual ~NpcAnimation(); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); - virtual void runAnimation(float timepassed); void updateParts(); void removeEntities(NifOgre::EntityList &entities); void removeIndividualPart(int type); @@ -98,6 +93,13 @@ public: void removePartGroup(int group); void addPartGroup(int group, int priority, std::vector& parts); +public: + NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, + MWWorld::InventoryStore& inv, int visibilityFlags); + virtual ~NpcAnimation(); + + virtual void runAnimation(float timepassed); + void forceUpdate(); }; From be74859f05257b0cbf3ba8884b39df8570a2d14d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 08:03:28 -0800 Subject: [PATCH 317/916] Avoid some unnecessary copying when calling addPartGroup --- apps/openmw/mwrender/npcanimation.cpp | 10 ++++------ apps/openmw/mwrender/npcanimation.hpp | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e4eea6c71..4fddb2020 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -228,15 +228,13 @@ void NpcAnimation::updateParts() { prio = ((slotlist[i].numReserveParts+1)<<1) + 0; const ESM::Clothing *clothes = store->get()->mBase; - std::vector parts = clothes->mParts.mParts; - addPartGroup(slotlist[i].slot, prio, parts); + addPartGroup(slotlist[i].slot, prio, clothes->mParts.mParts); } else if(store->getTypeName() == typeid(ESM::Armor).name()) { prio = ((slotlist[i].numReserveParts+1)<<1) + 1; const ESM::Armor *armor = store->get()->mBase; - std::vector parts = armor->mParts.mParts; - addPartGroup(slotlist[i].slot, prio, parts); + addPartGroup(slotlist[i].slot, prio, armor->mParts.mParts); } for(int res = 0;res < slotlist[i].numReserveParts;res++) @@ -392,11 +390,11 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, return true; } -void NpcAnimation::addPartGroup(int group, int priority, std::vector &parts) +void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts) { for(std::size_t i = 0; i < parts.size(); i++) { - ESM::PartReference &part = parts[i]; + const ESM::PartReference &part = parts[i]; const MWWorld::Store &partStore = MWBase::Environment::get().getWorld()->getStore().get(); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 1a121be07..161091317 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -91,7 +91,7 @@ private: bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); void removePartGroup(int group); - void addPartGroup(int group, int priority, std::vector& parts); + void addPartGroup(int group, int priority, const std::vector &parts); public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, From 44031ec3d73aa1bf3f03c22bfe9b515be56e9d0d Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Wed, 9 Jan 2013 08:11:20 -0800 Subject: [PATCH 318/916] fleshed out BSAArchive and DirArchive. Implemented both lists & finds, with pattern matching. Conflicts: components/bsa/bsa_archive.cpp --- apps/openmw/engine.cpp | 3 - components/bsa/bsa_archive.cpp | 258 ++++++++++++++++++++------------- 2 files changed, 160 insertions(+), 101 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8c288a2ee..b19cafab7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -164,9 +164,6 @@ void OMW::Engine::loadBSA() dataDirectory = iter->string(); std::cout << "Data dir " << dataDirectory << std::endl; Bsa::addDir(dataDirectory, mFSStrict); - - // Workaround until resource listing capabilities are added to DirArchive, we need those to list available splash screens - addResourcesDirectory (dataDirectory); } } diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 011b81351..9913fb8aa 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -37,28 +37,142 @@ namespace using namespace Ogre; using namespace Bsa; -struct ciLessBoost : std::binary_function +struct PathPatternMatcher { - bool operator() (const std::string & s1, const std::string & s2) const { - //case insensitive version of is_less - return boost::ilexicographical_compare(s1, s2); - } -}; - -struct pathComparer -{ -private: - std::string find; - -public: - pathComparer(const std::string& toFind) : find(toFind) { } - - bool operator() (const std::string& other) + PathPatternMatcher (char const * pattern) : pattern (pattern) { - return boost::iequals(find, other); + } + + bool operator () (char const * input) + { + char const * p = pattern; + char const * i = input; + + while (*p && *i) + { + if (*p == '*') + { + ++p; + + while (*i && *i != *p && *i != '/' && *i != '\\') + ++i; + } + else + if (*p == '?') + { + if (*i == '/' || *i == '\\') + break; + + ++i, ++p; + } + if (*p == '/' || *p == '\\') + { + if (*i != '/' && *i != '\\') + break; + + ++i, ++p; + } + else + { + if (*i != *p) + break; + + ++i, ++p; + } + } + + return *p == 0 && *i == 0; + } + +private: + char const * pattern; +}; + +struct FileNameGatherer +{ + StringVectorPtr ptr; + + FileNameGatherer (StringVectorPtr ptr) : ptr (ptr) + { + } + + void operator () (std::string const & filename) const + { + ptr->push_back (filename); } }; +struct FileInfoGatherer +{ + Archive const * archive; + FileInfoListPtr ptr; + + FileInfoGatherer (Archive const * archive, FileInfoListPtr ptr) : + archive (archive), ptr (ptr) + { + } + + void operator () (std::string filename) const + { + FileInfo fi; + + std::size_t pt = filename.rfind ('/'); + if (pt == std::string::npos) + pt = 0; + + fi.archive = const_cast (archive); + fi.path = filename.substr (0, pt); + fi.filename = filename.substr (pt); + fi.compressedSize = fi.uncompressedSize = 0; + + ptr->push_back(fi); + } +}; + +template +void matchFiles (bool recursive, std::string const & pattern, file_iterator begin, file_iterator end, filename_extractor filenameExtractor, match_handler matchHandler) +{ + if (recursive && pattern == "*") + { + for (file_iterator i = begin; i != end; ++i) + matchHandler (filenameExtractor (*i)); + } + else + { + PathPatternMatcher matcher (pattern.c_str ()); + + if (recursive) + { + for (file_iterator i = begin; i != end; ++i) + { + char const * filename = filenameExtractor (*i); + char const * matchable_part = filename; + + for (char const * j = matchable_part; *j; ++j) + { + if (*j == '/' || *j == '\\') + matchable_part = j + 1; + } + + if (matcher (matchable_part)) + matchHandler (filename); + } + } + else + { + for (file_iterator i = begin; i != end; ++i) + { + char const * filename = filenameExtractor (*i); + + if (matcher (filename)) + matchHandler (filename); + } + } + } +} + + + static bool fsstrict = false; /// An OGRE Archive wrapping a BSAFile archive @@ -94,6 +208,11 @@ class DirArchive: public Ogre::Archive return mIndex.find (normalized); } + static char const * extractFilename (index::value_type const & entry) + { + return entry.first.c_str (); + } + public: DirArchive(const String& name) @@ -143,27 +262,20 @@ public: StringVectorPtr list(bool recursive = true, bool dirs = false) { - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - std::cout << "DirArchive<" << getName () << ">::list" << std::endl; - return ptr; + return find ("*", recursive, dirs); } FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) { - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - std::cout << "DirArchive<" << getName () << ">::listFileInfo" << std::endl; - return ptr; + return findFileInfo ("*", recursive, dirs); } StringVectorPtr find(const String& pattern, bool recursive = true, bool dirs = false) { + std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); StringVectorPtr ptr = StringVectorPtr(new StringVector()); - - if (pattern == "*") - for (index::const_iterator i = mIndex.begin (); i != mIndex.end (); ++i) - ptr->push_back (i->first); - + matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, FileNameGatherer (ptr)); return ptr; } @@ -178,21 +290,20 @@ public: bool dirs = false) const { FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); + FileInfoGatherer gatherer (this, ptr); - index::const_iterator i = lookup_filename (pattern); + std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); + + index::const_iterator i = mIndex.find (normalizedPattern); if (i != mIndex.end ()) { - FileInfo fi; + gatherer (i->first); + } + else + { - std::size_t npos = i->first.rfind ('/'); - - fi.archive = this; - fi.filename = npos != std::string::npos ? i->first.substr (npos) : i->first; - fi.path = npos != std::string::npos ? i->first.substr (0, npos) : ""; - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); + matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, gatherer); } return ptr; @@ -203,6 +314,11 @@ class BSAArchive : public Archive { BSAFile arc; + static char const * extractFilename (BSAFile::FileStruct const & entry) + { + return entry.name; + } + public: BSAArchive(const String& name) : Archive(name, "BSA") @@ -230,26 +346,18 @@ public: return arc.exists(filename.c_str()); } - bool cexists(const String& filename) const { - return arc.exists(filename.c_str()); - } - time_t getModifiedTime(const String&) { return 0; } // This is never called as far as I can see. StringVectorPtr list(bool recursive = true, bool dirs = false) { - //std::cout << "list(" << recursive << ", " << dirs << ")\n"; - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - return ptr; + return find ("*", recursive, dirs); } // Also never called. FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) { - //std::cout << "listFileInfo(" << recursive << ", " << dirs << ")\n"; - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - return ptr; + return findFileInfo ("*", recursive, dirs); } // After load() is called, find("*") is called once. It doesn't seem @@ -258,17 +366,9 @@ public: StringVectorPtr find(const String& pattern, bool recursive = true, bool dirs = false) { - //std::cout << "find(" << pattern << ", " << recursive - // << ", " << dirs << ")\n"; - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - - BSAFile::FileList const & files = arc.getList (); - - if (pattern == "*") - for (BSAFile::FileList::const_iterator i = files.begin (); i != files.end (); ++i) - ptr->push_back (i->name); - - return ptr; + StringVectorPtr ptr = StringVectorPtr(new StringVector()); + matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileNameGatherer (ptr)); + return ptr; } /* Gets called once for each of the ogre formats, *.program, @@ -281,47 +381,9 @@ public: */ FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, bool dirs = false) const - { - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - - // Check if the file exists (only works for single files - wild - // cards and recursive search isn't implemented.) - if(cexists(pattern)) - { - FileInfo fi; - fi.archive = this; - fi.filename = pattern; - // It apparently doesn't matter that we return bogus - // information - fi.path = ""; - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } - - return ptr; - } - - FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, - bool dirs = false) { FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - - // Check if the file exists (only works for single files - wild - // cards and recursive search isn't implemented.) - if(cexists(pattern)) - { - FileInfo fi; - fi.archive = this; - fi.filename = pattern; - // It apparently doesn't matter that we return bogus - // information - fi.path = ""; - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } - + matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileInfoGatherer (this, ptr)); return ptr; } }; From 6ca87e108fb17f0f73d181439d7330d3bf321f6d Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Wed, 9 Jan 2013 08:12:19 -0800 Subject: [PATCH 319/916] updated loading screen to use the resource managers pattern matching when finding files --- apps/openmw/mwgui/loadingscreen.cpp | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index a508bcd34..cb80e0c36 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -214,27 +214,14 @@ namespace MWGui void LoadingScreen::changeWallpaper () { if (mResources.isNull ()) - { - mResources = Ogre::StringVectorPtr (new Ogre::StringVector); - - Ogre::StringVectorPtr resources = Ogre::ResourceGroupManager::getSingleton ().listResourceNames ("General", false); - for (Ogre::StringVector::const_iterator it = resources->begin(); it != resources->end(); ++it) - { - if (it->size() < 6) - continue; - std::string start = it->substr(0, 6); - boost::to_lower(start); - - if (start == "splash") - mResources->push_back (*it); - } - } + mResources = Ogre::ResourceGroupManager::getSingleton ().findResourceNames ("General", "Splash_*.tga"); if (mResources->size()) { - std::string randomSplash = mResources->at (rand() % mResources->size()); + std::string const & randomSplash = mResources->at (rand() % mResources->size()); Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); + mBackgroundImage->setImageTexture (randomSplash); } else From c4c8295e0b0144adc8ba3f1f77b55594c553bbe0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 9 Jan 2013 09:10:59 -0800 Subject: [PATCH 320/916] Rename NIFLoader to Loader, and update some comments --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 6 ++---- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 6 +++--- components/nifogre/ogre_nif_loader.cpp | 22 +++++++++++++++------- components/nifogre/ogre_nif_loader.hpp | 23 +++-------------------- 6 files changed, 25 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 59dcd451b..b8016d087 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -43,7 +43,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mInsert = node; assert(mInsert); - mEntityList = NifOgre::NIFLoader::createEntities(mInsert, model); + mEntityList = NifOgre::Loader::createEntities(mInsert, model); if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4fddb2020..ab4c7fa7c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -11,8 +11,6 @@ #include "renderconst.hpp" -using namespace Ogre; -using namespace NifOgre; namespace MWRender { @@ -299,8 +297,8 @@ void NpcAnimation::updateParts() NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename) { - NifOgre::EntityList entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename, - mInsert, mesh); + NifOgre::EntityList entities = NifOgre::Loader::createEntities(mEntityList.mSkelBase, bonename, + mInsert, mesh); std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 4c3b1166b..d0087e8dc 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -93,7 +93,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, mesh); + NifOgre::EntityList entities = NifOgre::Loader::createEntities(insert, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) { const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index c8a6ca0ef..0602fc8bb 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -324,7 +324,7 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); + NifOgre::EntityList entities = NifOgre::Loader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { Entity* night1_ent = entities.mEntities[i]; @@ -349,7 +349,7 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); + entities = NifOgre::Loader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* atmosphere_ent = entities.mEntities[i]; @@ -363,7 +363,7 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::NIFLoader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); + entities = NifOgre::Loader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); for(size_t i = 0;i < entities.mEntities.size();i++) { Entity* clouds_ent = entities.mEntities[i]; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index cfc0d8397..f078d90c9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -148,8 +148,12 @@ public: }; -class NIFSkeletonLoader : public Ogre::ManualResourceLoader { - +/** Manual resource loader for NIF skeletons. This is the main class + responsible for translating the internal NIF skeleton structure into + something Ogre can use (includes animations and node TextKeyData). + */ +class NIFSkeletonLoader : public Ogre::ManualResourceLoader +{ static void warn(const std::string &msg) { std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; @@ -754,6 +758,10 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String std::map NIFMaterialLoader::MaterialMap; +/** Manual resource loader for NIF meshes. This is the main class + responsible for translating the internal NIF mesh structure into + something Ogre can use. + */ class NIFMeshLoader : Ogre::ManualResourceLoader { std::string mName; @@ -1106,7 +1114,7 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshInfoMap; static MeshInfoMap sMeshInfoMap; -MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList Loader::load(const std::string &name, const std::string &skelName, const std::string &group) { MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); if(meshiter != sMeshInfoMap.end()) @@ -1145,7 +1153,7 @@ MeshInfoList NIFLoader::load(const std::string &name, const std::string &skelNam return meshes; } -EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) +EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; @@ -1192,9 +1200,9 @@ EntityList NIFLoader::createEntities(Ogre::SceneNode *parentNode, std::string na return entitylist; } -EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, const std::string &group) +EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, const std::string &group) { EntityList entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 4ed52a84a..f87d7d3c2 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -31,17 +31,12 @@ #include #include -namespace Nif -{ - class Node; - class Transformation; - class NiTriShape; -} +// FIXME: This namespace really doesn't do anything Nif-specific. Any supportable +// model format should go through this. namespace NifOgre { -// FIXME: These should not be in NifOgre, it works agnostic of what model format is used typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { @@ -69,19 +64,7 @@ struct MeshInfo { }; typedef std::vector MeshInfoList; -/** Manual resource loader for NIF meshes. This is the main class - responsible for translating the internal NIF mesh structure into - something Ogre can use. - - You have to insert meshes manually into Ogre like this: - - NIFLoader::load("somemesh.nif"); - - This returns a list of meshes used by the model, as well as the names of - their parent nodes (as they pertain to the skeleton, which is optionally - returned in the second argument if it exists). - */ -class NIFLoader +class Loader { static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); From 5bfdb2449dbbb468340f7b817fa752ac4a6738e9 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 9 Jan 2013 18:53:14 +0000 Subject: [PATCH 321/916] allowed dropObjectOnGround to be used on npcs, not just player --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3401494ef..a576912c0 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -280,7 +280,7 @@ namespace MWBase /// @param cursor Y (relative 0-1) /// @return true if the object was placed, or false if it was rejected because the position is too far away - virtual void dropObjectOnGround (const MWWorld::Ptr& object) = 0; + virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object) = 0; virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 5ea1d1338..a2c3a318b 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -220,7 +220,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) if (world->canPlaceObject(mouseX, mouseY)) world->placeObject(object, mouseX, mouseY); else - world->dropObjectOnGround(object); + world->dropObjectOnGround(world->getPlayer().getPlayer(), object); MyGUI::PointerManager::getInstance().setPointer("arrow"); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7e0f1d7d3..6e2e5f3b7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1286,7 +1286,7 @@ namespace MWWorld } } - void World::dropObjectOnGround (const Ptr& object) + void World::dropObjectOnGround (const Ptr& actor, const Ptr& object) { MWWorld::Ptr::CellStore* cell = getPlayer().getPlayer().getCell(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e6d377e60..7e89c1d87 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -311,7 +311,7 @@ namespace MWWorld /// @param cursor Y (relative 0-1) /// @return true if the object was placed, or false if it was rejected because the position is too far away - virtual void dropObjectOnGround (const Ptr& object); + virtual void dropObjectOnGround (const Ptr& actor, const Ptr& object); virtual bool canPlaceObject(float cursorX, float cursorY); ///< @return true if it is possible to place on object at specified cursor location From bc73c5b1ecaa8001bdeeac46864d4e22026b104a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 20:08:59 +0100 Subject: [PATCH 322/916] enable directional lighting for character previews --- apps/openmw/mwrender/characterpreview.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b034e098b..a172d02b1 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -39,6 +39,15 @@ namespace MWRender void CharacterPreview::setup () { mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); + + /// \todo Read the fallback values from INIImporter (Inventory:Directional*) + Ogre::Light* l = mSceneMgr->createLight(); + l->setType (Ogre::Light::LT_DIRECTIONAL); + l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + l->setDiffuseColour (Ogre::ColourValue(1,1,1)); + + mSceneMgr->setAmbientLight (Ogre::ColourValue(0.5, 0.5, 0.5)); + mCamera = mSceneMgr->createCamera (mName); mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); @@ -72,7 +81,6 @@ namespace MWRender mViewport->setOverlaysEnabled(false); mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); mViewport->setShadowsEnabled(false); - mViewport->setMaterialScheme("local_map"); mViewport->setVisibilityMask (RV_PlayerPreview); mRenderTarget->setActive(true); mRenderTarget->setAutoUpdated (false); From 111e38ef25546836d243c9b14c72bd055478a53b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 20:18:26 +0100 Subject: [PATCH 323/916] Revert "fog now distance based instead of depth" This reverts commit 7ee038fdd7fcb51f901893ae0e6554a2f0cc3dc1. --- files/materials/objects.shader | 2 +- files/materials/openmw.configuration | 1 + files/materials/terrain.shader | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 25624351c..130de0f3d 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -265,7 +265,7 @@ #endif #if FOG - float fogValue = shSaturate((length(cameraPos.xyz-worldPos) - fogParams.y) * fogParams.w); + float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); #if UNDERWATER // regular fog only if fragment is above water diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index 2f84680f0..ee97451d3 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -1,5 +1,6 @@ configuration water_reflection { + fog false shadows false shadows_pssm false mrt_output false diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index dee733263..9494c1de9 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -337,7 +337,7 @@ #if FOG - float fogValue = shSaturate((length(cameraPos.xyz-worldPos) - fogParams.y) * fogParams.w); + float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); #if UNDERWATER // regular fog only if fragment is above water From 2dc0064cc252da5249d36d2963b129115a3edc69 Mon Sep 17 00:00:00 2001 From: eduard Date: Wed, 9 Jan 2013 20:51:52 +0100 Subject: [PATCH 324/916] more string lowercase --- apps/mwiniimporter/importer.cpp | 4 +- apps/opencs/model/world/idcollection.hpp | 11 ++--- apps/openmw/mwclass/container.cpp | 4 +- apps/openmw/mwclass/door.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwdialogue/filter.cpp | 41 +++++++------------ apps/openmw/mwdialogue/selectwrapper.cpp | 14 ++----- apps/openmw/mwgui/dialogue.cpp | 5 +-- apps/openmw/mwgui/loadingscreen.cpp | 6 ++- apps/openmw/mwmechanics/activespells.cpp | 4 +- .../mwmechanics/mechanicsmanagerimp.cpp | 28 ++++--------- .../mwmechanics/mechanicsmanagerimp.hpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwscript/guiextensions.cpp | 4 +- apps/openmw/mwscript/statsextensions.cpp | 24 +++++------ apps/openmw/mwworld/cells.cpp | 5 +-- apps/openmw/mwworld/cellstore.cpp | 10 +---- apps/openmw/mwworld/containerstore.cpp | 2 +- apps/openmw/mwworld/weather.cpp | 2 +- components/compiler/exprparser.cpp | 7 ++-- components/compiler/lineparser.cpp | 13 +++--- components/compiler/parser.cpp | 7 ++-- components/compiler/scanner.cpp | 8 ++-- components/compiler/stringparser.cpp | 3 +- components/files/filelibrary.cpp | 10 ++--- components/files/fileops.cpp | 5 ++- components/nifogre/ogre_nif_loader.cpp | 9 ++-- components/nifoverrides/nifoverrides.cpp | 5 ++- 28 files changed, 101 insertions(+), 139 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 6a7274e0a..077b62be1 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -7,6 +7,8 @@ #include #include #include +#include + MwIniImporter::MwIniImporter() : mVerbose(false) @@ -793,7 +795,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { std::string filetype(entry->substr(entry->length()-4, 3)); - std::transform(filetype.begin(), filetype.end(), filetype.begin(), ::tolower); + Misc::StringUtils::toLower(filetype); if(filetype.compare("esm") == 0) { esmFiles.push_back(*entry); diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 1b2d1e349..963997924 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -12,6 +12,7 @@ #include #include "columnbase.hpp" +#include namespace CSMWorld { @@ -152,10 +153,7 @@ namespace CSMWorld template void IdCollection::add (const ESXRecordT& record) { - std::string id; - - std::transform (record.mId.begin(), record.mId.end(), std::back_inserter (id), - (int(*)(int)) std::tolower); + std::string id = Misc::StringUtils::lowerCase(record.mId); std::map::iterator iter = mIndex.find (id); @@ -281,10 +279,7 @@ namespace CSMWorld template int IdCollection::searchId (const std::string& id) const { - std::string id2; - - std::transform (id.begin(), id.end(), std::back_inserter (id2), - (int(*)(int)) std::tolower); + std::string id2 = Misc::StringUtils::lowerCase(id); std::map::const_iterator iter = mIndex.find (id2); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 76c1c40f1..bbe005955 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -97,11 +97,11 @@ namespace MWClass // make key id lowercase std::string keyId = ptr.getCellRef().mKey; - std::transform(keyId.begin(), keyId.end(), keyId.begin(), ::tolower); + Misc::StringUtils::toLower(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { std::string refId = it->getCellRef().mRefID; - std::transform(refId.begin(), refId.end(), refId.begin(), ::tolower); + Misc::StringUtils::toLower(refId); if (refId == keyId) { hasKey = true; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 09a15a2cb..fb6329939 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -84,11 +84,11 @@ namespace MWClass // make key id lowercase std::string keyId = ptr.getCellRef().mKey; - std::transform(keyId.begin(), keyId.end(), keyId.begin(), ::tolower); + Misc::StringUtils::toLower(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { std::string refId = it->getCellRef().mRefID; - std::transform(refId.begin(), refId.end(), refId.begin(), ::tolower); + Misc::StringUtils::toLower(refId); if (refId == keyId) { hasKey = true; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 83a002447..586f9638d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -65,7 +65,7 @@ namespace MWClass if (!ref->mBase->mFaction.empty()) { std::string faction = ref->mBase->mFaction; - boost::algorithm::to_lower(faction); + Misc::StringUtils::toLower(faction); if(ref->mBase->mNpdt52.mGold != -10) { data->mNpcStats.getFactionRanks()[faction] = (int)ref->mBase->mNpdt52.mRank; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 0deef7fd0..7c590c8ef 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -17,24 +17,11 @@ #include "selectwrapper.hpp" -namespace -{ - std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } -} - bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const { // actor id if (!info.mActor.empty()) - if (toLower (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor)) + if ( Misc::StringUtils::lowerCase (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor)) return false; bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); @@ -47,7 +34,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const MWWorld::LiveCellRef *cellRef = mActor.get(); - if (toLower (info.mRace)!=toLower (cellRef->mBase->mRace)) + if (Misc::StringUtils::lowerCase (info.mRace)!= Misc::StringUtils::lowerCase (cellRef->mBase->mRace)) return false; } @@ -59,7 +46,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const MWWorld::LiveCellRef *cellRef = mActor.get(); - if (toLower (info.mClass)!=toLower (cellRef->mBase->mClass)) + if ( Misc::StringUtils::lowerCase (info.mClass)!= Misc::StringUtils::lowerCase (cellRef->mBase->mClass)) return false; } @@ -70,7 +57,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const return false; MWMechanics::NpcStats& stats = MWWorld::Class::get (mActor).getNpcStats (mActor); - std::map::iterator iter = stats.getFactionRanks().find (toLower (info.mNpcFaction)); + std::map::iterator iter = stats.getFactionRanks().find ( Misc::StringUtils::lowerCase (info.mNpcFaction)); if (iter==stats.getFactionRanks().end()) return false; @@ -99,7 +86,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const if (!info.mPcFaction.empty()) { MWMechanics::NpcStats& stats = MWWorld::Class::get (player).getNpcStats (player); - std::map::iterator iter = stats.getFactionRanks().find (toLower (info.mPcFaction)); + std::map::iterator iter = stats.getFactionRanks().find (Misc::StringUtils::lowerCase (info.mPcFaction)); if(iter==stats.getFactionRanks().end()) return false; @@ -111,7 +98,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const // check cell if (!info.mCell.empty()) - if (toLower (player.getCell()->mCell->mName) != toLower (info.mCell)) + if (Misc::StringUtils::lowerCase (player.getCell()->mCell->mName) != Misc::StringUtils::lowerCase (info.mCell)) return false; return true; @@ -242,7 +229,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con std::string name = select.getName(); for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - if (toLower(iter->getCellRef().mRefID) == name) + if (Misc::StringUtils::lowerCase(iter->getCellRef().mRefID) == name) sum += iter->getRefData().getCount(); return sum; @@ -408,23 +395,23 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_Id: - return select.getName()==toLower (MWWorld::Class::get (mActor).getId (mActor)); + return select.getName()==Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor)); case SelectWrapper::Function_Faction: - return toLower (mActor.get()->mBase->mFaction)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mFaction)==select.getName(); case SelectWrapper::Function_Class: - return toLower (mActor.get()->mBase->mClass)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mClass)==select.getName(); case SelectWrapper::Function_Race: - return toLower (mActor.get()->mBase->mRace)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mRace)==select.getName(); case SelectWrapper::Function_Cell: - return toLower (mActor.getCell()->mCell->mName)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)==select.getName(); case SelectWrapper::Function_SameGender: @@ -433,8 +420,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_SameRace: - return toLower (mActor.get()->mBase->mRace)!= - toLower (player.get()->mBase->mRace); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mRace)!= + Misc::StringUtils::lowerCase (player.get()->mBase->mRace); case SelectWrapper::Function_SameFaction: diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 1462ee8ba..9cc528a11 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -8,18 +8,10 @@ #include #include +#include + namespace { - std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } - template bool selectCompareImp (char comp, T1 value1, T2 value2) { @@ -307,5 +299,5 @@ bool MWDialogue::SelectWrapper::selectCompare (bool value) const std::string MWDialogue::SelectWrapper::getName() const { - return toLower (mSelect.mSelectRule.substr (5)); + return Misc::StringUtils::lowerCase (mSelect.mSelectRule.substr (5)); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 5b04cc37e..f62bf2a05 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -37,10 +37,7 @@ namespace { std::string lower_string(const std::string& str) { - std::string lowerCase; - - std::transform (str.begin(), str.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + std::string lowerCase = Misc::StringUtils::lowerCase (str); return lowerCase; } diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index a508bcd34..41283842d 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -6,6 +6,7 @@ #include #include + #include #include @@ -16,6 +17,9 @@ #include "../mwbase/windowmanager.hpp" +#include + + namespace MWGui { @@ -223,7 +227,7 @@ namespace MWGui if (it->size() < 6) continue; std::string start = it->substr(0, 6); - boost::to_lower(start); + Misc::StringUtils::toLower(start); if (start == "splash") mResources->push_back (*it); diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index f53ccdce3..ee1e9da36 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -263,11 +263,11 @@ namespace MWMechanics bool ActiveSpells::isSpellActive(std::string id) const { - boost::algorithm::to_lower(id); + Misc::StringUtils::toLower(id); for (TContainer::iterator iter = mSpells.begin(); iter != mSpells.end(); ++iter) { std::string left = iter->first; - boost::algorithm::to_lower(left); + Misc::StringUtils::toLower(left); if (iter->first == id) return true; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 079f8520b..dae417d44 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -377,16 +377,6 @@ namespace MWMechanics mUpdatePlayer = true; } - std::string toLower (const std::string& name) - { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - return lowerCase; - } - int MechanicsManager::getDerivedDisposition(const MWWorld::Ptr& ptr) { MWMechanics::NpcStats npcSkill = MWWorld::Class::get(ptr).getNpcStats(ptr); @@ -398,7 +388,7 @@ namespace MWMechanics MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); MWMechanics::NpcStats playerNpcStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); - if (toLower(npc->mBase->mRace) == toLower(player->mBase->mRace)) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispRaceMod")->getFloat(); + if (Misc::StringUtils::lowerCase(npc->mBase->mRace) == Misc::StringUtils::lowerCase(player->mBase->mRace)) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispRaceMod")->getFloat(); x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispPersonalityMult")->getFloat() * (playerStats.getAttribute(ESM::Attribute::Personality).getModified() - MWBase::Environment::get().getWorld()->getStore().get().find("fDispPersonalityBase")->getFloat()); @@ -408,21 +398,21 @@ namespace MWMechanics std::string npcFaction = ""; if(!npcSkill.getFactionRanks().empty()) npcFaction = npcSkill.getFactionRanks().begin()->first; - if (playerNpcStats.getFactionRanks().find(toLower(npcFaction)) != playerNpcStats.getFactionRanks().end()) + if (playerNpcStats.getFactionRanks().find(Misc::StringUtils::lowerCase(npcFaction)) != playerNpcStats.getFactionRanks().end()) { - for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.begin(); - it != MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.end(); it++) + for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.begin(); + it != MWBase::Environment::get().getWorld()->getStore().get().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.end(); it++) { - if(toLower(it->mFaction) == toLower(npcFaction)) reaction = it->mReaction; + if(Misc::StringUtils::lowerCase(it->mFaction) == Misc::StringUtils::lowerCase(npcFaction)) reaction = it->mReaction; } - rank = playerNpcStats.getFactionRanks().find(toLower(npcFaction))->second; + rank = playerNpcStats.getFactionRanks().find(Misc::StringUtils::lowerCase(npcFaction))->second; } else if (npcFaction != "") { - for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.begin(); - it != MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.end();it++) + for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.begin(); + it != MWBase::Environment::get().getWorld()->getStore().get().find(Misc::StringUtils::lowerCase(npcFaction))->mReactions.end();it++) { - if(playerNpcStats.getFactionRanks().find(toLower(it->mFaction)) != playerNpcStats.getFactionRanks().end() ) + if(playerNpcStats.getFactionRanks().find(Misc::StringUtils::lowerCase(it->mFaction)) != playerNpcStats.getFactionRanks().end() ) { if(it->mReactionmReaction; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f8d470a4e..d3a97db36 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -90,6 +90,7 @@ namespace MWMechanics virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); + void toLower(std::string npcFaction); ///< Perform a persuasion action on NPC }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index e6a8006e2..d33bdda91 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -80,7 +80,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; mBodyPrefix = "b_n_" + mNpc->mRace; - std::transform(mBodyPrefix.begin(), mBodyPrefix.end(), mBodyPrefix.begin(), ::tolower); + Misc::StringUtils::toLower(mBodyPrefix); mInsert = node; assert(mInsert); diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 7d437f3c0..bfe69c79e 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -102,7 +102,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { std::string cell = (runtime.getStringLiteral (runtime[0].mInteger)); - boost::algorithm::to_lower(cell); + Misc::StringUtils::toLower(cell); runtime.pop(); // "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's House as well." @@ -115,7 +115,7 @@ namespace MWScript for (; it != cells.extEnd(); ++it) { std::string name = it->mName; - boost::algorithm::to_lower(name); + Misc::StringUtils::toLower(name); if (name.find(cell) != std::string::npos) MWBase::Environment::get().getWindowManager()->addVisitedLocation ( it->mName, diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 9e630aedf..e2e260c32 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -512,7 +512,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - boost::algorithm::to_lower(factionID); + Misc::StringUtils::toLower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -541,7 +541,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - boost::algorithm::to_lower(factionID); + Misc::StringUtils::toLower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -574,7 +574,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } - boost::algorithm::to_lower(factionID); + Misc::StringUtils::toLower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -612,7 +612,7 @@ namespace MWScript factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; } } - boost::algorithm::to_lower(factionID); + Misc::StringUtils::toLower(factionID); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(factionID!="") { @@ -714,7 +714,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - boost::algorithm::to_lower (factionId); + Misc::StringUtils::toLower (factionId); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); runtime.push ( @@ -750,7 +750,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - boost::algorithm::to_lower (factionId); + Misc::StringUtils::toLower (factionId); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, value); @@ -785,7 +785,7 @@ namespace MWScript if (factionId.empty()) throw std::runtime_error ("failed to determine faction"); - boost::algorithm::to_lower (factionId); + Misc::StringUtils::toLower (factionId); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, @@ -830,11 +830,11 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); std::string race = runtime.getStringLiteral(runtime[0].mInteger); - boost::algorithm::to_lower(race); + Misc::StringUtils::toLower(race); runtime.pop(); std::string npcRace = ptr.get()->mBase->mRace; - boost::algorithm::to_lower(npcRace); + Misc::StringUtils::toLower(npcRace); runtime.push (npcRace == race); } @@ -878,7 +878,7 @@ namespace MWScript factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; } } - boost::algorithm::to_lower(factionID); + Misc::StringUtils::toLower(factionID); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(factionID!="") { @@ -929,7 +929,7 @@ namespace MWScript if(factionID!="") { std::set& expelled = MWWorld::Class::get(player).getNpcStats(player).getExpelled (); - boost::algorithm::to_lower(factionID); + Misc::StringUtils::toLower(factionID); expelled.insert(factionID); } } @@ -965,7 +965,7 @@ namespace MWScript if(factionID!="") { std::set& expelled = MWWorld::Class::get(player).getNpcStats(player).getExpelled (); - boost::algorithm::to_lower(factionID); + Misc::StringUtils::toLower(factionID); expelled.erase (factionID); } } diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 696a469f7..622c8a10a 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -153,10 +153,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce if (cell.mState==Ptr::CellStore::State_Preloaded) { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + std::string lowerCase = Misc::StringUtils::lowerCase(name); if (std::binary_search (cell.mIds.begin(), cell.mIds.end(), lowerCase)) { diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 1ef2d36a2..fb5e45556 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -56,10 +56,7 @@ namespace MWWorld // Get each reference in turn while (mCell->getNextRef (esm, ref)) { - std::string lowerCase; - - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + std::string lowerCase = Misc::StringUtils::lowerCase (ref.mRefID); mIds.push_back (lowerCase); } @@ -82,10 +79,7 @@ namespace MWWorld // Get each reference in turn while(mCell->getNextRef(esm, ref)) { - std::string lowerCase; - - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID); int rec = store.find(ref.mRefID); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index e47f2191a..db4537daf 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -37,7 +37,7 @@ namespace bool compare_string_ci(std::string str1, std::string str2) { - boost::algorithm::to_lower(str1); + Misc::StringUtils::toLower(str1); return str1 == str2; } } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 19bc881f7..917a8d7d4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -497,7 +497,7 @@ void WeatherManager::update(float duration) if (exterior) { std::string regionstr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion; - boost::algorithm::to_lower(regionstr); + Misc::StringUtils::toLower(regionstr); if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 52192625b..027f3de71 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -14,6 +14,7 @@ #include "stringparser.hpp" #include "extensions.hpp" #include "context.hpp" +#include namespace Compiler { @@ -199,8 +200,8 @@ namespace Compiler { mMemberOp = false; - std::string name2 = toLower (name); - std::string id = toLower (mExplicit); + std::string name2 = Misc::StringUtils::lowerCase (name); + std::string id = Misc::StringUtils::lowerCase (mExplicit); char type = getContext().getMemberType (name2, id); @@ -285,7 +286,7 @@ namespace Compiler { start(); - std::string name2 = toLower (name); + std::string name2 = Misc::StringUtils::lowerCase (name); char type = mLocals.getType (name2); diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index a4cbc1ffe..210d18dc9 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -8,6 +8,7 @@ #include "locals.hpp" #include "generator.hpp" #include "extensions.hpp" +#include namespace Compiler { @@ -91,13 +92,13 @@ namespace Compiler return false; } - std::string name2 = toLower (name); + std::string name2 = Misc::StringUtils::lowerCase (name); char type = mLocals.getType (name2); if (type!=' ') { - getErrorHandler().error ("can't re-declare local variable", loc); + getErrorHandler().error ("catoLowern't re-declare local variable", loc); SkipParser skip (getErrorHandler(), getContext()); scanner.scan (skip); return false; @@ -112,7 +113,7 @@ namespace Compiler if (mState==SetState) { - std::string name2 = toLower (name); + std::string name2 = Misc::StringUtils::lowerCase (name); mName = name2; // local variable? @@ -138,7 +139,7 @@ namespace Compiler if (mState==SetMemberVarState) { - mMemberName = toLower (name); + mMemberName = Misc::StringUtils::lowerCase (name); char type = getContext().getMemberType (mMemberName, mName); if (type!=' ') @@ -205,13 +206,13 @@ namespace Compiler if (mState==BeginState && getContext().isId (name)) { mState = PotentialExplicitState; - mExplicit = toLower (name); + mExplicit = Misc::StringUtils::lowerCase (name); return true; } if (mState==BeginState && mAllowExpression) { - std::string name2 = toLower (name); + std::string name2 = Misc::StringUtils::lowerCase (name); char type = mLocals.getType (name2); diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 90368eee0..896458e48 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -9,6 +9,8 @@ #include "exception.hpp" #include "scanner.hpp" +#include + namespace Compiler { // Report the error and throw an exception. @@ -57,10 +59,7 @@ namespace Compiler std::string Parser::toLower (const std::string& name) { - std::string lowerCase; - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + std::string lowerCase = Misc::StringUtils::lowerCase(name); return lowerCase; } diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 962699dfa..7f43c36a5 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -11,6 +11,8 @@ #include "parser.hpp" #include "extensions.hpp" +#include + namespace Compiler { bool Scanner::get (char& c) @@ -268,11 +270,7 @@ namespace Compiler int i = 0; - std::string lowerCase; - lowerCase.reserve (name.size()); - - std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); + std::string lowerCase = Misc::StringUtils::lowerCase(name); for (; keywords[i]; ++i) if (lowerCase==keywords[i]) diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index 396a88c78..09c902131 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -6,6 +6,7 @@ #include "scanner.hpp" #include "generator.hpp" +#include namespace Compiler { @@ -22,7 +23,7 @@ namespace Compiler { start(); if (mSmashCase) - Generator::pushString (mCode, mLiterals, toLower (name)); + Generator::pushString (mCode, mLiterals, Misc::StringUtils::lowerCase (name)); else Generator::pushString (mCode, mLiterals, name); diff --git a/components/files/filelibrary.cpp b/components/files/filelibrary.cpp index ce67f0c66..ce2d95f57 100644 --- a/components/files/filelibrary.cpp +++ b/components/files/filelibrary.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include <../components/misc/stringops.hpp> namespace Files { @@ -45,14 +45,14 @@ namespace Files if( !acceptableExtensions.empty() ) { fileExtension = boost::filesystem::path (listIter->extension()).string(); - boost::algorithm::to_lower(fileExtension); + Misc::StringUtils::toLower(fileExtension); if(!containsVectorString(acceptableExtensions, fileExtension)) continue; } type = boost::filesystem::path (listIter->parent_path().leaf()).string(); if (!strict) - boost::algorithm::to_lower(type); + Misc::StringUtils::toLower(type); mMap[type].push_back(*listIter); // std::cout << "Added path: " << listIter->string() << " in section "<< type < #include +#include <../components/misc/stringops.hpp> namespace Files { @@ -87,7 +88,7 @@ bool isFile(const char *name) if (!strict) { - boost::algorithm::to_lower(toFindStr); + Misc::StringUtils::toLower(toFindStr); } for (Files::PathContainer::const_iterator it = list.begin(); it != list.end(); ++it) @@ -99,7 +100,7 @@ bool isFile(const char *name) if (!strict) { - boost::algorithm::to_lower(fullPath); + Misc::StringUtils::toLower(fullPath); } if(endingMatches(fullPath, toFindStr)) { diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 31d873489..489acb108 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -1003,7 +1004,7 @@ public: if(mSkelName.length() > 0 && mName != mSkelName) fullname += "@skel="+mSkelName; - std::transform(fullname.begin(), fullname.end(), fullname.begin(), ::tolower); + Misc::StringUtils::toLower(fullname); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { @@ -1045,8 +1046,8 @@ static MeshPairMap sMeshPairMap; MeshPairList NIFLoader::load(std::string name, std::string skelName, const std::string &group) { - std::transform(name.begin(), name.end(), name.begin(), ::tolower); - std::transform(skelName.begin(), skelName.end(), skelName.begin(), ::tolower); + Misc::StringUtils::toLower(name); + Misc::StringUtils::toLower(skelName); MeshPairMap::const_iterator meshiter = sMeshPairMap.find(name+"@skel="+skelName); if(meshiter != sMeshPairMap.end()) @@ -1159,7 +1160,7 @@ EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bo Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first); if(ent->hasSkeleton()) { - std::transform(meshes[i].second.begin(), meshes[i].second.end(), meshes[i].second.begin(), ::tolower); + Misc::StringUtils::toLower(meshes[i].second); if(meshes[i].second.length() < filter.length() || meshes[i].second.compare(0, filter.length(), filter) != 0) diff --git a/components/nifoverrides/nifoverrides.cpp b/components/nifoverrides/nifoverrides.cpp index 1c8fefd24..191b4ac2f 100644 --- a/components/nifoverrides/nifoverrides.cpp +++ b/components/nifoverrides/nifoverrides.cpp @@ -2,7 +2,8 @@ #include -#include +#include <../components/misc/stringops.hpp> + using namespace NifOverrides; @@ -19,7 +20,7 @@ TransparencyResult Overrides::getTransparencyOverride(const std::string& texture result.first = false; std::string tex = texture; - boost::to_lower(tex); + Misc::StringUtils::toLower(tex); Ogre::ConfigFile::SectionIterator seci = mTransparencyOverrides.getSectionIterator(); while (seci.hasMoreElements()) From bd8d793fec20fe751651abfcebd7ef0704ffbb8b Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 21:41:40 +0100 Subject: [PATCH 325/916] Removing gamma correction due to caused inconsistencies. --- files/materials/core.h | 7 ++++--- files/materials/objects.shader | 2 +- files/materials/terrain.shader | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/files/materials/core.h b/files/materials/core.h index 1c9ea1d1d..0e46369ef 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -1,7 +1,8 @@ -#define gammaCorrectRead(v) pow(max(v, 0.00001f), float3(gammaCorrection,gammaCorrection,gammaCorrection)) -#define gammaCorrectOutput(v) pow(max(v, 0.00001f), float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) - +//#define gammaCorrectRead(v) pow(max(v, 0.00001f), float3(gammaCorrection,gammaCorrection,gammaCorrection)) +//#define gammaCorrectOutput(v) pow(max(v, 0.00001f), float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) +#define gammaCorrectRead(v) v +#define gammaCorrectOutput(v) v #if SH_HLSL == 1 || SH_CG == 1 diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 130de0f3d..c68705c42 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -112,7 +112,7 @@ shUniform(float, far) @shAutoConstant(far, far_clip_distance) #endif - shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) + //shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) #if LIGHTING shInput(float3, normalPassthrough) diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 9494c1de9..dfe998210 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -137,7 +137,7 @@ shSampler2D(normalMap) // global normal map - shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) + //shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) @shForeach(@shPropertyString(num_blendmaps)) From b8c6f6640b9f01c0f7925f33819e1da73b34c509 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 21:56:26 +0100 Subject: [PATCH 326/916] Fixing water <-> waterfall blending issues (Sort of... the second part will follow later) --- apps/openmw/mwrender/water.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e8f099640..80fe54707 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -48,7 +48,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); - mWater->setRenderQueueGroup(RQG_Water); mWater->setCastShadows(false); mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); @@ -324,7 +323,11 @@ void Water::applyRTT() mReflectionTarget = rtt; sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mReflectionTexture->getName()); + + mWater->setRenderQueueGroup(RQG_Water); } + else + mWater->setRenderQueueGroup(RQG_Alpha); } void Water::applyVisibilityMask() From d3c0851aa72cb47b977cf6377ae03c73a2859335 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 22:08:42 +0100 Subject: [PATCH 327/916] Changed light attenuation back to linear in all cases, this seems to be what MW does. --- apps/openmw/mwrender/objects.cpp | 7 +++---- apps/openmw/mwrender/water.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index ee36126f8..810d7af41 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -238,17 +238,16 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f info.time = Ogre::Math::RangeRandom(-500, +500); info.phase = Ogre::Math::RangeRandom(-500, +500); - // adjust the lights depending if we're in an interior or exterior cell - // quadratic means the light intensity falls off quite fast, resulting in a - // dark, atmospheric environment (perfect for exteriors) - // for interiors, we want more "warm" lights, so use linear attenuation. + // changed to linear to look like morrowind bool quadratic = false; + /* if (!lightOutQuadInLin) quadratic = lightQuadratic; else { quadratic = !info.interior; } + */ if (!quadratic) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 80fe54707..a16a23b26 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -315,7 +315,7 @@ void Water::applyRTT() vp->setOverlaysEnabled(false); vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setShadowsEnabled(false); - // use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain) + // use fallback techniques without shadows and without mrt vp->setMaterialScheme("water_reflection"); rtt->addListener(this); rtt->setActive(true); From 3517635cfd86b017ad6e842be388bbb9149a5bce Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 9 Jan 2013 21:16:45 +0000 Subject: [PATCH 328/916] added Drop and DropSoulGem functions --- apps/openmw/mwscript/docs/vmformat.txt | 7 ++- apps/openmw/mwscript/miscextensions.cpp | 64 +++++++++++++++++++++++++ apps/openmw/mwworld/worldimp.cpp | 4 +- 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7c009f095..283f149de 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -311,4 +311,9 @@ op 0x20001f4: AddSoulGem, explicit reference op 0x20001f5: RemoveSoulGem op 0x20001f6: RemoveSoulGem, explicit reference op 0x20001f7: PlayBink -opcodes 0x20001f8-0x3ffffff unused +op 0x20001f8: Drop +op 0x20001f9: Drop, explicit reference +op 0x20001fa: DropSoulGem +op 0x20001fb: DropSoulGem, explicit reference + +opcodes 0x20001fa-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index a348a0a49..53c3c2f7b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -383,6 +383,60 @@ namespace MWScript } }; + template + class OpDrop : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + + MWWorld::Ptr ptr = R()(runtime); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); + + + for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) + { + if (::Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) + { + MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); + break; + } + } + } + }; + + template + class OpDropSoulGem : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + + MWWorld::Ptr ptr = R()(runtime); + + std::string soul = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); + + + for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) + { + if (::Misc::StringUtils::ciEqual(iter->getCellRef().mSoul, soul)) + { + MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); + break; + } + } + } + }; + template class OpGetAttacked : public Interpreter::Opcode0 { @@ -495,6 +549,10 @@ namespace MWScript const int opcodeAddSoulGemExplicit = 0x20001f4; const int opcodeRemoveSoulGem = 0x20001f5; const int opcodeRemoveSoulGemExplicit = 0x20001f6; + const int opcodeDrop = 0x20001f8; + const int opcodeDropExplicit = 0x20001f9; + const int opcodeDropSoulGem = 0x20001fa; + const int opcodeDropSoulGemExplicit = 0x20001fb; const int opcodeGetAttacked = 0x20001d3; const int opcodeGetAttackedExplicit = 0x20001d4; const int opcodeGetWeaponDrawn = 0x20001d7; @@ -538,6 +596,8 @@ namespace MWScript extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); + extensions.registerInstruction ("drop", "c", opcodeDrop, opcodeDropExplicit); + extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit); extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit); @@ -576,6 +636,10 @@ namespace MWScript interpreter.installSegment5 (opcodeAddSoulGemExplicit, new OpAddSoulGem); interpreter.installSegment5 (opcodeRemoveSoulGem, new OpRemoveSoulGem); interpreter.installSegment5 (opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem); + interpreter.installSegment5 (opcodeDrop, new OpDrop); + interpreter.installSegment5 (opcodeDropExplicit, new OpDrop); + interpreter.installSegment5 (opcodeDropSoulGem, new OpDropSoulGem); + interpreter.installSegment5 (opcodeDropSoulGemExplicit, new OpDropSoulGem); interpreter.installSegment5 (opcodeGetAttacked, new OpGetAttacked); interpreter.installSegment5 (opcodeGetAttackedExplicit, new OpGetAttacked); interpreter.installSegment5 (opcodeGetWeaponDrawn, new OpGetWeaponDrawn); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6e2e5f3b7..f49b4bf9b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1288,10 +1288,10 @@ namespace MWWorld void World::dropObjectOnGround (const Ptr& actor, const Ptr& object) { - MWWorld::Ptr::CellStore* cell = getPlayer().getPlayer().getCell(); + MWWorld::Ptr::CellStore* cell = actor.getCell(); ESM::Position pos = - getPlayer().getPlayer().getRefData().getPosition(); + actor.getRefData().getPosition(); Ogre::Vector3 orig = Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]); From 455ec0996df77bea43903741b37eda7b57aecb51 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 22:27:58 +0100 Subject: [PATCH 329/916] Shaders & textures are now loaded upon loading the NIF, instead of when the object becomes visible in the camera frustum. Should improve responsiveness. --- components/nifogre/ogre_nif_loader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 31d873489..35060e50b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -656,6 +656,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String else instance->getMaterial ()->setShadowCasterMaterial ("openmw_shadowcaster_noalpha"); + sh::Factory::getInstance ()._ensureMaterial (matname, "Default"); + // As of yet UNTESTED code from Chris: /*pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); From 35015ef11002547835851979ad6ffd9e48487ceb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 9 Jan 2013 23:11:15 +0100 Subject: [PATCH 330/916] Change default settings to use no object shaders and per vertex lighting, as some lights in MW look clearly broken with per pixel lighting enabled (e.g. fireplace in census office, ghostfence) --- files/settings-default.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 1768b2f5e..26546c2b1 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -96,7 +96,7 @@ fps = 0 crosshair = true [Objects] -shaders = true +shaders = false # Max. number of lights that affect objects. Setting to 1 will only reflect sunlight # Note: has no effect when shaders are turned off @@ -132,7 +132,7 @@ num lights = 8 # Enable this to get fancy-looking water with reflections and refractions # Only available if object shaders are on # All the settings below have no effect if this is false -shader = true +shader = false rtt size = 512 reflect terrain = true @@ -142,7 +142,7 @@ reflect actors = false reflect misc = false # Enable underwater effect. It is not resource intensive, so only disable it if you have problems. -underwater effect = true +underwater effect = false [Sound] # Device name. Blank means default From 8486a5153592ee0505c0b5072e6dd7a48e65d54c Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Wed, 9 Jan 2013 22:55:28 +0000 Subject: [PATCH 331/916] fixed drop amounts thanks to zinnschlag --- apps/openmw/mwscript/miscextensions.cpp | 34 ++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 53c3c2f7b..f329e30d9 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -396,6 +396,9 @@ namespace MWScript std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); + Interpreter::Type_Integer amount = runtime[0].mInteger; + runtime.pop(); + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); @@ -403,7 +406,19 @@ namespace MWScript { if (::Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) { - MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); + if(iter->getRefData().getCount() <= amount) + { + MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); + iter->getRefData().setCount(0); + } + else + { + int original = iter->getRefData().getCount(); + iter->getRefData().setCount(amount); + MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); + iter->getRefData().setCount(original - amount); + } + break; } } @@ -430,7 +445,20 @@ namespace MWScript { if (::Misc::StringUtils::ciEqual(iter->getCellRef().mSoul, soul)) { - MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); + + if(iter->getRefData().getCount() <= 1) + { + MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); + iter->getRefData().setCount(0); + } + else + { + int original = iter->getRefData().getCount(); + iter->getRefData().setCount(1); + MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); + iter->getRefData().setCount(original - 1); + } + break; } } @@ -596,7 +624,7 @@ namespace MWScript extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); extensions.registerInstruction ("addsoulgem", "cc", opcodeAddSoulGem, opcodeAddSoulGemExplicit); extensions.registerInstruction ("removesoulgem", "c", opcodeRemoveSoulGem, opcodeRemoveSoulGemExplicit); - extensions.registerInstruction ("drop", "c", opcodeDrop, opcodeDropExplicit); + extensions.registerInstruction ("drop", "cl", opcodeDrop, opcodeDropExplicit); extensions.registerInstruction ("dropsoulgem", "c", opcodeDropSoulGem, opcodeDropSoulGemExplicit); extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit); From 55769aaf911cb06ffa856d5a9d14a77c5f4b3ada Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 10 Jan 2013 01:46:00 +0100 Subject: [PATCH 332/916] Fix selection buffer (i.e. item selection on the inventory character preview) when object shaders were disabled --- apps/openmw/engine.cpp | 4 +--- files/materials/selection.mat | 1 + files/materials/water.mat | 2 +- files/materials/water.shader | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8c288a2ee..31eb68fa7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -391,8 +391,6 @@ void OMW::Engine::go() MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos); } - std::cout << "\nPress Q/ESC or close window to exit.\n"; - mOgre->getRoot()->addFrameListener (this); // Play some good 'ol tunes @@ -420,7 +418,7 @@ void OMW::Engine::go() // Save user settings settings.saveUser(settingspath); - std::cout << "Quitting peacefully.\n"; + std::cout << "Quitting peacefully." << std::endl; } void OMW::Engine::activate() diff --git a/files/materials/selection.mat b/files/materials/selection.mat index a76dd7179..2cb92f884 100644 --- a/files/materials/selection.mat +++ b/files/materials/selection.mat @@ -1,5 +1,6 @@ material SelectionColour { + allow_fixed_function false pass { vertex_program selection_vertex diff --git a/files/materials/water.mat b/files/materials/water.mat index dcea5a0d0..a5f9f2ec9 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -2,7 +2,7 @@ material Water { pass { - emissive 0.6 0.7 1.0 + emissive 1.0 1.0 1.0 ambient 0 0 0 diffuse 0 0 0 1 specular 0 0 0 32 diff --git a/files/materials/water.shader b/files/materials/water.shader index 6bd277eab..9ebea0f00 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -42,7 +42,7 @@ SH_START_PROGRAM { - shOutputColour(0).xyz = shSample(animatedTexture, UV * 15).xyz * float3(0.6, 0.7, 1.0); + shOutputColour(0).xyz = shSample(animatedTexture, UV * 15).xyz * float3(1.0, 1.0, 1.0); shOutputColour(0).w = 0.7; float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); From 7f2d71554eea9067e3077534e17f04817f0ed47c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 04:16:18 -0800 Subject: [PATCH 333/916] Use the correct offset when building static geometry from an entity --- apps/openmw/mwrender/objects.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index d0087e8dc..bd5f95c24 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -193,13 +193,15 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - for(size_t i = 0;i < entities.mEntities.size();i++) + std::vector::reverse_iterator iter = entities.mEntities.rbegin(); + while(iter != entities.mEntities.rend()) { - Ogre::Entity *ent = entities.mEntities[i]; - insert->detachObject(ent); - sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); + Ogre::Node *node = (*iter)->getParentNode(); + sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); - mRenderer.getScene()->destroyEntity(ent); + (*iter)->detachFromParent(); + mRenderer.getScene()->destroyEntity(*iter); + iter++; } } } From e8ac3976b58e9d93cb5f8fe9c78aae391d88e05a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 06:35:06 -0800 Subject: [PATCH 334/916] Fix some subentity assumptions --- apps/openmw/mwrender/sky.cpp | 74 +++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0602fc8bb..3592eb46e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -205,44 +205,48 @@ unsigned int Moon::getPhaseInt() const void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) { - // Get the vertex colour buffer of this mesh - const Ogre::VertexElement* ves_diffuse = ent->getMesh()->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE ); - HardwareVertexBufferSharedPtr colourBuffer = ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource()); - - // Lock - void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL); - - // Iterate over all vertices - int vertex_size = colourBuffer->getVertexSize(); - float * currentVertex = NULL; - for (unsigned int i=0; igetNumVertices(); ++i) + for(unsigned int idx = 0;idx < ent->getNumSubEntities();idx++) { - // Get a pointer to the vertex colour - ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex ); + Ogre::SubMesh *submesh = ent->getSubEntity(idx)->getSubMesh(); + // Get the vertex colour buffer of this mesh + const Ogre::VertexElement* ves_diffuse = submesh->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE ); + HardwareVertexBufferSharedPtr colourBuffer = submesh->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource()); - unsigned char alpha=0; - if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row - else if (meshType == 1) + // Lock + void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL); + + // Iterate over all vertices + int vertex_size = colourBuffer->getVertexSize(); + for (unsigned int i=0; igetNumVertices(); ++i) { - if (i>= 49 && i <= 64) alpha = 0; // bottom-most row - else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row - else alpha = 255; + // Get a pointer to the vertex colour + float *currentVertex = NULL; + ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex ); + + unsigned char alpha=0; + if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row + else if (meshType == 1) + { + if (i>= 49 && i <= 64) alpha = 0; // bottom-most row + else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row + else alpha = 255; + } + // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 + uint8 tmpR = static_cast(255); + uint8 tmpG = static_cast(255); + uint8 tmpB = static_cast(255); + uint8 tmpA = static_cast(alpha); + + // Modify + *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); + + // Move to the next vertex + pData = static_cast (pData) + vertex_size; } - // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 - uint8 tmpR = static_cast(255); - uint8 tmpG = static_cast(255); - uint8 tmpB = static_cast(255); - uint8 tmpA = static_cast(alpha); - // Modify - *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); - - // Move to the next vertex - pData = static_cast (pData) + vertex_size; + // Unlock + colourBuffer->unlock(); } - - // Unlock - ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock(); } SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) @@ -356,7 +360,8 @@ void SkyManager::create() atmosphere_ent->setCastShadows(false); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); - atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); + for(unsigned int j = 0;j < atmosphere_ent->getNumSubEntities();j++) + atmosphere_ent->getSubEntity (j)->setMaterialName("openmw_atmosphere"); ModVertexAlpha(atmosphere_ent, 0); } @@ -369,7 +374,8 @@ void SkyManager::create() Entity* clouds_ent = entities.mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); - clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); + for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) + clouds_ent->getSubEntity(j)->setMaterialName("openmw_clouds"); clouds_ent->setCastShadows(false); ModVertexAlpha(clouds_ent, 1); From 771a5f73166d53c219cfe35763d487cda62be1df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 08:35:24 -0800 Subject: [PATCH 335/916] Add the beginnings of a character controller --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/character.cpp | 26 ++++++++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 9 +++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwmechanics/character.cpp create mode 100644 apps/openmw/mwmechanics/character.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090..563c9e422 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,7 +62,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells + mechanicsmanagerimp stat character creaturestats magiceffects movement actors drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate ) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp new file mode 100644 index 000000000..319c4fe9b --- /dev/null +++ b/apps/openmw/mwmechanics/character.cpp @@ -0,0 +1,26 @@ +/* + * OpenMW - The completely unofficial reimplementation of Morrowind + * + * This file (character.cpp) is part of the OpenMW package. + * + * OpenMW is distributed as free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * version 3, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 3 along with this program. If not, see + * http://www.gnu.org/licenses/ . + */ + +#include "character.hpp" + + +namespace MWMechanics +{ + +} diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp new file mode 100644 index 000000000..cab269112 --- /dev/null +++ b/apps/openmw/mwmechanics/character.hpp @@ -0,0 +1,9 @@ +#ifndef GAME_MWMECHANICS_CHARACTER_HPP +#define GAME_MWMECHANICS_CHARACTER_HPP + +namespace MWMechanics +{ + +} + +#endif /* GAME_MWMECHANICS_CHARACTER_HPP */ From 97f8c73d91a01f9682539aa0cee44b08f585caeb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 10 Jan 2013 11:09:33 -0800 Subject: [PATCH 336/916] Remove some useless parameters SceneNode::setVisibility merely passes the value to its attached object, of which there are none at the point it would be called. Additionally, the method is always called with enabled=true anyway. --- apps/openmw/mwrender/actors.cpp | 33 +++++++++++++++------------------ apps/openmw/mwrender/actors.hpp | 2 +- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index fc5a46d12..ec7c9d073 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -27,14 +27,9 @@ Actors::~Actors(){ void Actors::setMwRoot(Ogre::SceneNode* root){ mMwRoot = root; } -void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){ - insertBegin(ptr, true, true); - NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors); - - mAllActors[ptr] = anim; -} -void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ +void Actors::insertBegin (const MWWorld::Ptr& ptr) +{ Ogre::SceneNode* cellnode; if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) { @@ -66,26 +61,28 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ // Rotates first around z, then y, then x insert->setOrientation(xr*yr*zr); - if (!enabled) - insert->setVisible (false); ptr.getRefData().setBaseNode(insert); - - } -void Actors::insertCreature (const MWWorld::Ptr& ptr){ - insertBegin(ptr, true, true); - CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr); - //mAllActors.insert(std::pair(ptr,anim)); +void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv) +{ + insertBegin(ptr); + NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), inv, RV_Actors); + delete mAllActors[ptr]; + mAllActors[ptr] = anim; +} +void Actors::insertCreature (const MWWorld::Ptr& ptr) +{ + insertBegin(ptr); + CreatureAnimation* anim = new CreatureAnimation(ptr); delete mAllActors[ptr]; mAllActors[ptr] = anim; - //mAllActors.push_back(&anim);*/ } bool Actors::deleteObject (const MWWorld::Ptr& ptr) { - delete mAllActors[ptr]; - mAllActors.erase(ptr); + delete mAllActors[ptr]; + mAllActors.erase(ptr); if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode()) { diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 71be0bd7b..6ea6a8137 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -25,7 +25,7 @@ namespace MWRender Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); void setMwRoot(Ogre::SceneNode* root); - void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); + void insertBegin (const MWWorld::Ptr& ptr); void insertCreature (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); bool deleteObject (const MWWorld::Ptr& ptr); From c71656493da4c5a5634d6510b851de0b8c26ac3a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jan 2013 01:23:24 +0100 Subject: [PATCH 337/916] Ingredient effects now correctly hide until the player has discovered them --- apps/openmw/mwclass/ingredient.cpp | 13 +++++++++++++ apps/openmw/mwgui/widgets.cpp | 8 ++++++-- apps/openmw/mwgui/widgets.hpp | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 1be8d66b3..7ad8f1b47 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -12,6 +12,9 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/actioneat.hpp" +#include "../mwworld/player.hpp" + +#include "../mwmechanics/npcstats.hpp" #include "../mwgui/tooltips.hpp" @@ -154,6 +157,10 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); } + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); + int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); + MWGui::Widgets::SpellEffectList list; for (int i=0; i<4; ++i) { @@ -163,6 +170,12 @@ namespace MWClass params.mEffectID = ref->mBase->mData.mEffectID[i]; params.mAttribute = ref->mBase->mData.mAttributes[i]; params.mSkill = ref->mBase->mData.mSkills[i]; + + params.mKnown = ( (i == 0 && alchemySkill >= 15) + || (i == 1 && alchemySkill >= 30) + || (i == 2 && alchemySkill >= 45) + || (i == 3 && alchemySkill >= 60)); + list.push_back(params); } info.effects = list; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 82e112826..f932c1f03 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -390,8 +390,13 @@ void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) void MWSpellEffect::updateWidgets() { - if (!mWindowManager) + if (!mEffectParams.mKnown) + { + mTextWidget->setCaption ("?"); + mRequestedWidth = mTextWidget->getTextSize().width + 24; + mImageWidget->setImageTexture (""); return; + } const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -400,7 +405,6 @@ void MWSpellEffect::updateWidgets() store.get().search(mEffectParams.mEffectID); assert(magicEffect); - assert(mWindowManager); std::string pt = mWindowManager->getGameSettingString("spoint", ""); std::string pts = mWindowManager->getGameSettingString("spoints", ""); diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 4ac5383f7..7cbb5e53a 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -37,12 +37,15 @@ namespace MWGui , mEffectID(-1) , mNoTarget(false) , mIsConstant(false) + , mKnown(true) { } bool mNoTarget; // potion effects for example have no target (target is always the player) bool mIsConstant; // constant effect means that duration will not be displayed + bool mKnown; // is this effect known to the player? (If not, will display as a question mark instead) + // value of -1 here means the effect is unknown to the player short mEffectID; From d469415e59ab55e16f01b24a83c422d8dfa1f60e Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 8 Jan 2013 09:45:01 -0800 Subject: [PATCH 338/916] factored out two function from OMW::Engine::go The initialization code inside Engine::go is now in two function it calls prior to running the main loop. --- apps/openmw/engine.cpp | 54 +++++++++++++++++++++++++++--------------- apps/openmw/engine.hpp | 7 ++++++ 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b19cafab7..661bf4a52 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -240,18 +240,9 @@ void OMW::Engine::setNewGame(bool newGame) mNewGame = newGame; } -// Initialise and enter main loop. - -void OMW::Engine::go() +std::string OMW::Engine::loadSettings (Settings::Manager & settings) { - assert (!mCellName.empty()); - assert (!mMaster.empty()); - assert (!mOgre); - - mOgre = new OEngine::Render::OgreRenderer; - // Create the settings manager and load default settings file - Settings::Manager settings; const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg"; const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg"; @@ -272,10 +263,6 @@ void OMW::Engine::go() else if (boost::filesystem::exists(globaldefault)) settings.loadUser(globaldefault); - // Get the path for the keybinder xml file - std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); - bool keybinderUserExists = boost::filesystem::exists(keybinderUser); - mFpsLevel = settings.getInt("fps", "HUD"); // load nif overrides @@ -285,6 +272,11 @@ void OMW::Engine::go() else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); + return settingspath; +} + +void OMW::Engine::prepareEngine (Settings::Manager & settings) +{ std::string renderSystem = settings.getString("render system", "Video"); if (renderSystem == "") { @@ -294,6 +286,9 @@ void OMW::Engine::go() renderSystem = "OpenGL Rendering Subsystem"; #endif } + + mOgre = new OEngine::Render::OgreRenderer; + mOgre->configure( mCfgMgr.getLogPath().string(), renderSystem, @@ -365,6 +360,11 @@ void OMW::Engine::go() mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); // Sets up the input system + + // Get the path for the keybinder xml file + std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); + bool keybinderUserExists = boost::filesystem::exists(keybinderUser); + mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, MWBase::Environment::get().getWorld()->getPlayer(), *MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists)); @@ -388,13 +388,8 @@ void OMW::Engine::go() MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos); } - std::cout << "\nPress Q/ESC or close window to exit.\n"; - mOgre->getRoot()->addFrameListener (this); - // Play some good 'ol tunes - MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); - // scripts if (mCompileAll) { @@ -407,10 +402,31 @@ void OMW::Engine::go() << "%)" << std::endl; } +} + +// Initialise and enter main loop. + +void OMW::Engine::go() +{ + assert (!mCellName.empty()); + assert (!mMaster.empty()); + assert (!mOgre); + + Settings::Manager settings; + std::string settingspath; + + settingspath = loadSettings (settings); + + prepareEngine (settings); + + // Play some good 'ol tunes + MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore")); if (!mStartupScript.empty()) MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript); + std::cout << "\nPress Q/ESC or close window to exit.\n"; + // Start the main rendering loop mOgre->start(); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 601cc7765..363bb8a10 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "mwbase/environment.hpp" @@ -103,6 +104,12 @@ namespace OMW virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); + /// Load settings from various files, returns the path to the user settings file + std::string loadSettings (Settings::Manager & settings); + + /// Prepare engine for game play + void prepareEngine (Settings::Manager & settings); + public: Engine(Files::ConfigurationManager& configurationManager); virtual ~Engine(); From 9d4f8c67223625e5a21d9095888532847e2e8be5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 3 Jan 2013 08:57:04 -0800 Subject: [PATCH 339/916] changed bullet_nif_loader to not modifiy NIF file The code in bullet_nif_loader was modifing the loaded NIF file as part of processing. Currently this is OK since the NIF file will be thrown away immediately, but it causes problems when trying to share loaded NIF files. --- components/nifbullet/bullet_nif_loader.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 42f6a8e68..0c8de0c27 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -165,7 +165,7 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node) } void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, - const Nif::Transformation *trafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) + const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) { // Accumulate the flags from all the child nodes. This works for all @@ -208,23 +208,23 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, } } + Nif::Transformation childTrafo = node->trafo; - if (trafo) + if (parentTrafo) { // Get a non-const reference to the node's data, since we're // overwriting it. TODO: Is this necessary? - Nif::Transformation &final = node->trafo; // For both position and rotation we have that: // final_vector = old_vector + old_rotation*new_vector*old_scale - final.pos = trafo->pos + trafo->rotation*final.pos*trafo->scale; + childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale; // Merge the rotations together - final.rotation = trafo->rotation * final.rotation; + childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation; // Scale - final.scale *= trafo->scale; + childTrafo.scale *= parentTrafo->scale; } @@ -249,14 +249,14 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, { if (!list[i].empty()) { - handleNode(list[i].getPtr(), flags,&node->trafo,hasCollisionNode,isCollisionNode,raycastingOnly); + handleNode(list[i].getPtr(), flags,&childTrafo,hasCollisionNode,isCollisionNode,raycastingOnly); } } } else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->mCollide = !(flags&0x800); - handleNiTriShape(dynamic_cast(node), flags,node->trafo.rotation,node->trafo.pos,node->trafo.scale,raycastingOnly); + handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); } else if(node->recType == Nif::RC_RootCollisionNode) { @@ -265,7 +265,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, for (int i=0; itrafo, hasCollisionNode,true,raycastingOnly); + handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly); } } } From 0989b44b415d56246a02d754733e971b7a8458bf Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 3 Jan 2013 09:33:19 -0800 Subject: [PATCH 340/916] spread some const around NIF loading --- components/nif/nif_file.cpp | 4 ++-- components/nif/node.hpp | 4 ++-- components/nifbullet/bullet_nif_loader.cpp | 18 +++++++-------- components/nifbullet/bullet_nif_loader.hpp | 10 ++++----- components/nifogre/ogre_nif_loader.cpp | 26 +++++++++++----------- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 3313d89ab..38ff5b270 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -211,14 +211,14 @@ void NiSkinInstance::post(NIFFile *nif) } } -Ogre::Matrix4 Node::getLocalTransform() +Ogre::Matrix4 Node::getLocalTransform() const { Ogre::Matrix4 mat4(Ogre::Matrix4::IDENTITY); mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation)); return mat4; } -Ogre::Matrix4 Node::getWorldTransform() +Ogre::Matrix4 Node::getWorldTransform() const { if(parent != NULL) return parent->getWorldTransform() * getLocalTransform(); diff --git a/components/nif/node.hpp b/components/nif/node.hpp index f7d3c6e96..07e7868cc 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -111,8 +111,8 @@ public: boneIndex = ind; } - Ogre::Matrix4 getLocalTransform(); - Ogre::Matrix4 getWorldTransform(); + Ogre::Matrix4 getLocalTransform() const; + Ogre::Matrix4 getWorldTransform() const; }; struct NiNode : Node diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 0c8de0c27..cea8c4b52 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -51,7 +51,7 @@ ManualBulletShapeLoader::~ManualBulletShapeLoader() } -btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 &m) +btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 const &m) { Ogre::Quaternion oquat(m); btQuaternion quat; @@ -62,7 +62,7 @@ btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 &m) return quat; } -btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 &v) +btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) { return btVector3(v[0], v[1], v[2]); } @@ -138,7 +138,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) } } -bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node) +bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) { if (node->recType == Nif::RC_NiNode) { @@ -164,7 +164,7 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node) return false; } -void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, +void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) { @@ -181,7 +181,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, } // Check for extra data - Nif::Extra *e = node; + Nif::Extra const *e = node; while (!e->extra.empty()) { // Get the next extra data in the list @@ -232,7 +232,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, { - btVector3 boxsize = getbtVector((node->boundXYZ)); + btVector3 boxsize = getbtVector(node->boundXYZ); cShape->boxTranslation = node->boundPos; cShape->boxRotation = node->boundRot; @@ -243,7 +243,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, // For NiNodes, loop through children if (node->recType == Nif::RC_NiNode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; + Nif::NodeList const &list = ((Nif::NiNode const *)node)->children; int n = list.length(); for (int i=0; irecType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->mCollide = !(flags&0x800); - handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); + handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); } else if(node->recType == Nif::RC_RootCollisionNode) { @@ -270,7 +270,7 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, } } -void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, +void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, bool raycastingOnly) { assert(shape != NULL); diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index 2190fda1b..520878ce1 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -79,25 +79,25 @@ public: void load(const std::string &name,const std::string &group); private: - btQuaternion getbtQuat(Ogre::Matrix3 &m); + btQuaternion getbtQuat(Ogre::Matrix3 const &m); - btVector3 getbtVector(Ogre::Vector3 &v); + btVector3 getbtVector(Ogre::Vector3 const &v); /** *Parse a node. */ - void handleNode(Nif::Node *node, int flags, + void handleNode(Nif::Node const *node, int flags, const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); /** *Helper function */ - bool hasRootCollisionNode(Nif::Node* node); + bool hasRootCollisionNode(Nif::Node const * node); /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(Nif::NiTriShape *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); + void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); std::string resourceName; std::string resourceGroup; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 489acb108..207d01ff6 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -187,7 +187,7 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) } -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) { Ogre::Bone *bone; if(!skel->hasBone(node->name)) @@ -255,7 +255,7 @@ void loadResource(Ogre::Resource *resource) Nif::NIFFile nif(skel->getName()); const Nif::Node *node = dynamic_cast(nif.getRecord(0)); - std::vector ctrls; + std::vector ctrls; buildBones(skel, node, ctrls); std::vector targets; @@ -266,7 +266,7 @@ void loadResource(Ogre::Resource *resource) float maxtime = 0.0f; for(size_t i = 0;i < ctrls.size();i++) { - Nif::NiKeyframeController *ctrl = ctrls[i]; + Nif::NiKeyframeController const *ctrl = ctrls[i]; maxtime = std::max(maxtime, ctrl->timeStop); Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); if(target != NULL) @@ -289,8 +289,8 @@ void loadResource(Ogre::Resource *resource) for(size_t i = 0;i < ctrls.size();i++) { - Nif::NiKeyframeController *kfc = ctrls[i]; - Nif::NiKeyframeData *kf = kfc->data.getPtr(); + Nif::NiKeyframeController const *kfc = ctrls[i]; + Nif::NiKeyframeData const *kf = kfc->data.getPtr(); /* Get the keyframes and make sure they're sorted first to last */ Nif::QuaternionKeyList quatkeys = kf->mRotations; @@ -711,7 +711,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape) + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -909,18 +909,18 @@ class NIFMeshLoader : Ogre::ManualResourceLoader sub->setMaterialName(mMaterialName); } - bool findTriShape(Ogre::Mesh *mesh, Nif::Node *node) + bool findTriShape(Ogre::Mesh *mesh, Nif::Node const *node) { if(node->recType == Nif::RC_NiTriShape && mShapeName == node->name) { - handleNiTriShape(mesh, dynamic_cast(node)); + handleNiTriShape(mesh, dynamic_cast(node)); return true; } - Nif::NiNode *ninode = dynamic_cast(node); + Nif::NiNode const *ninode = dynamic_cast(node); if(ninode) { - Nif::NodeList &children = ninode->children; + Nif::NodeList const &children = ninode->children; for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) @@ -957,7 +957,7 @@ public: } Nif::NIFFile nif(mName); - Nif::Node *node = dynamic_cast(nif.getRecord(0)); + Nif::Node const *node = dynamic_cast(nif.getRecord(0)); findTriShape(mesh, node); } @@ -1062,10 +1062,10 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: } // The first record is assumed to be the root node - Nif::Record *r = nif.getRecord(0); + Nif::Record const *r = nif.getRecord(0); assert(r != NULL); - Nif::Node *node = dynamic_cast(r); + Nif::Node const *node = dynamic_cast(r); if(node == NULL) { nif.warn("First record in file was not a node, but a "+ From d5ebd6654dc87de27bcc01f5634503acd7c71a6a Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 10:58:50 -0800 Subject: [PATCH 341/916] cache loaded NIF files to eliminate reloads Created a NIF file caching mechanism to prevent the system from reloading a NIF during a startup and cell changes. --- apps/openmw/engine.cpp | 2 + apps/openmw/mwworld/scene.cpp | 2 + components/nif/nif_file.cpp | 149 +++++++++++++++++++++ components/nif/nif_file.hpp | 37 +++-- components/nifbullet/bullet_nif_loader.cpp | 3 +- components/nifogre/ogre_nif_loader.cpp | 10 +- 6 files changed, 187 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 661bf4a52..4413e98f4 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -277,6 +277,8 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) void OMW::Engine::prepareEngine (Settings::Manager & settings) { + Nif::NIFFile::CacheLock cachelock; + std::string renderSystem = settings.getString("render system", "Video"); if (renderSystem == "") { diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6b9abf508..b917a8916 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -172,6 +172,8 @@ namespace MWWorld void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) { + Nif::NIFFile::CacheLock cachelock; + mRendering.preCellChange(mCurrentCell); // remove active diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 38ff5b270..07d34b9ea 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -34,10 +34,159 @@ #include "controller.hpp" #include + +//TODO: when threading is needed, enable these +//#include +//#include + using namespace std; using namespace Nif; using namespace Misc; +class NIFFile::LoadedCache +{ + //TODO: enable this to make cache thread safe... + //typedef boost::mutex mutex; + + struct mutex + { + void lock () {}; + void unlock () {} + }; + + typedef boost::lock_guard lock_guard; + typedef std::map < std::string, boost::weak_ptr > loaded_map; + typedef std::vector < boost::shared_ptr > locked_files; + + static int sLockLevel; + static mutex sProtector; + static loaded_map sLoadedMap; + static locked_files sLockedFiles; + +public: + + static ptr create (const std::string &name) + { + lock_guard _ (sProtector); + + ptr result; + + // lookup the resource + loaded_map::iterator i = sLoadedMap.find (name); + + if (i == sLoadedMap.end ()) // it doesn't existing currently, + { // or hasn't in the very near past + + // create it now, for smoother threading if needed, the + // loading should be performed outside of the sLoaderMap + // lock and an alternate mechanism should be used to + // synchronize threads competing to load the same resource + result = boost::make_shared (name, psudo_private_modifier()); + + // if we are locking the cache add an extra reference + // to keep the file in memory + if (sLockLevel > 0) + sLockedFiles.push_back (result); + + // stash a reference to the resource so that future + // calls can benefit + sLoadedMap [name] = boost::weak_ptr (result); + } + else // it may (probably) still exists + { + // attempt to get the reference + result = i->second.lock (); + + if (!result) // resource is in the process of being destroyed + { + // create a new instance, to replace the one that has + // begun the irreversible process of being destroyed + result = boost::make_shared (name, psudo_private_modifier()); + + // respect the cache lock... + if (sLockLevel > 0) + sLockedFiles.push_back (result); + + // we potentially overwrite an expired pointer here + // but the other thread performing the delete on + // the previous copy of this resource will detect it + // and make sure not to erase the new reference + sLoadedMap [name] = boost::weak_ptr (result); + } + } + + // we made it! + return result; + } + + static void release (NIFFile * file) + { + lock_guard _ (sProtector); + + loaded_map::iterator i = sLoadedMap.find (file->filename); + + // its got to be in here, it just might not be us... + assert (i != sLoadedMap.end ()); + + // if weak_ptr is still expired, this resource hasn't been recreated + // between the initiation of the final release due to destruction + // of the last shared pointer and this thread acquiring the lock on + // the loader map + if (i->second.expired ()) + sLoadedMap.erase (i); + } + + static void lockCache () + { + lock_guard _ (sProtector); + + sLockLevel++; + } + + static void unlockCache () + { + locked_files resetList; + + { + lock_guard _ (sProtector); + + if (--sLockLevel) + sLockedFiles.swap(resetList); + } + + // this not necessary, but makes it clear that the + // deletion of the locked cache entries is being done + // outside the protection of sProtector + resetList.clear (); + } +}; + +int NIFFile::LoadedCache::sLockLevel = 0; +NIFFile::LoadedCache::mutex NIFFile::LoadedCache::sProtector; +NIFFile::LoadedCache::loaded_map NIFFile::LoadedCache::sLoadedMap; +NIFFile::LoadedCache::locked_files NIFFile::LoadedCache::sLockedFiles; + +// these three calls are forwarded to the cache implementation... +void NIFFile::lockCache () { LoadedCache::lockCache (); } +void NIFFile::unlockCache () { LoadedCache::unlockCache (); } +NIFFile::ptr NIFFile::create (const std::string &name) { return LoadedCache::create (name); } + +/// Open a NIF stream. The name is used for error messages. +NIFFile::NIFFile(const std::string &name, psudo_private_modifier) + : filename(name) +{ + inp = Ogre::ResourceGroupManager::getSingleton().openResource(name); + parse(); +} + +NIFFile::~NIFFile() +{ + LoadedCache::release (this); + + for(std::size_t i=0; i #include +#include +#include +#include +#include + #include #include "record.hpp" @@ -93,6 +98,14 @@ class NIFFile return u.f; } + class LoadedCache; + friend class LoadedCache; + + // attempt to protect NIFFile from misuse... + struct psudo_private_modifier {}; // this dirty little trick should optimize out + NIFFile (NIFFile const &); + void operator = (NIFFile const &); + public: /// Used for error handling void fail(const std::string &msg) @@ -108,19 +121,21 @@ public: << "File: "< ptr; - ~NIFFile() + /// Open a NIF stream. The name is used for error messages. + NIFFile(const std::string &name, psudo_private_modifier); + ~NIFFile(); + + static ptr create (const std::string &name); + static void lockCache (); + static void unlockCache (); + + struct CacheLock { - for(std::size_t i=0; i(resource); OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); - Nif::NIFFile nif(skel->getName()); + Nif::NIFFile::ptr pnif(Nif::NIFFile::create (skel->getName())); + Nif::NIFFile & nif = *pnif.get (); const Nif::Node *node = dynamic_cast(nif.getRecord(0)); std::vector ctrls; @@ -956,8 +957,8 @@ public: return; } - Nif::NIFFile nif(mName); - Nif::Node const *node = dynamic_cast(nif.getRecord(0)); + Nif::NIFFile::ptr nif = Nif::NIFFile::create (mName); + Nif::Node const *node = dynamic_cast(nif->getRecord(0)); findTriShape(mesh, node); } @@ -1054,7 +1055,8 @@ MeshPairList NIFLoader::load(std::string name, std::string skelName, const std:: return meshiter->second; MeshPairList &meshes = sMeshPairMap[name+"@skel="+skelName]; - Nif::NIFFile nif(name); + Nif::NIFFile::ptr pnif = Nif::NIFFile::create (name); + Nif::NIFFile &nif = *pnif.get (); if (nif.numRecords() < 1) { nif.warn("Found no records in NIF."); From 85bdb49d1b18b9653f5e35cbee397342b92edf2c Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Fri, 11 Jan 2013 09:10:48 +0100 Subject: [PATCH 342/916] Mix debug and release if necessary under non Windows systems. --- components/files/ogreplugin.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/components/files/ogreplugin.cpp b/components/files/ogreplugin.cpp index ca90fd30e..c319f7758 100644 --- a/components/files/ogreplugin.cpp +++ b/components/files/ogreplugin.cpp @@ -6,11 +6,6 @@ namespace Files { bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot) { - // Append plugin suffix if debugging. -#if defined(DEBUG) - pluginName = pluginName + OGRE_PLUGIN_DEBUG_SUFFIX; -#endif - #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE std::ostringstream verStream; verStream << "." << OGRE_VERSION_MAJOR << "." << OGRE_VERSION_MINOR << "." << OGRE_VERSION_PATCH; @@ -28,13 +23,28 @@ bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre:: pluginExt = ".so"; #endif - std::string pluginPath = pluginDir + "/" + pluginName + pluginExt; + // Append plugin suffix if debugging. + std::string pluginPath; +#if defined(DEBUG) + pluginPath = pluginDir + "/" + pluginName + OGRE_PLUGIN_DEBUG_SUFFIX + pluginExt; if (boost::filesystem::exists(pluginPath)) { - ogreRoot.loadPlugin(pluginPath); - return true; + ogreRoot.loadPlugin(pluginPath); + return true; } else { - return false; +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + return false; +#endif //OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + } +#endif //defined(DEBUG) + + pluginPath = pluginDir + "/" + pluginName + pluginExt; + if (boost::filesystem::exists(pluginPath)) { + ogreRoot.loadPlugin(pluginPath); + return true; + } + else { + return false; } } From ed3c23ad9af2eb310c32fb2563ae55777c2e4608 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jan 2013 01:18:36 +0100 Subject: [PATCH 343/916] Fixed crash on changing cell due to Utf8Encoder going out of scope --- apps/openmw/engine.cpp | 11 ++++++----- apps/openmw/engine.hpp | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4413e98f4..4f149efa1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -325,16 +325,13 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // cursor replacer (converts the cursor from the bsa so they can be used by mygui) MWGui::CursorReplace replacer; - // Create encoder - ToUTF8::Utf8Encoder encoder (mEncoding); - // Create the world mEnvironment.setWorld (new MWWorld::World (*mOgre, mFileCollections, mMaster, - mResDir, mCfgMgr.getCachePath(), mNewGame, &encoder, mFallbackMap, + mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, mActivationDistanceOverride)); //Load translation data - mTranslationDataStorage.setEncoder(&encoder); + mTranslationDataStorage.setEncoder(mEncoder); mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster); // Create window manager - this manages all the MW-specific GUI windows @@ -419,6 +416,10 @@ void OMW::Engine::go() settingspath = loadSettings (settings); + // Create encoder + ToUTF8::Utf8Encoder encoder (mEncoding); + mEncoder = &encoder; + prepareEngine (settings); // Play some good 'ol tunes diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 363bb8a10..e320c6991 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -62,6 +62,7 @@ namespace OMW { MWBase::Environment mEnvironment; ToUTF8::FromType mEncoding; + ToUTF8::Utf8Encoder* mEncoder; Files::PathContainer mDataDirs; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; From 30136eb4496b4e81e62548825ef468906db32029 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jan 2013 06:36:48 +0100 Subject: [PATCH 344/916] Update settings UI --- apps/openmw/mwgui/settingswindow.cpp | 60 +++++++++-------------- apps/openmw/mwgui/settingswindow.hpp | 3 +- apps/openmw/mwgui/windowmanagerimp.cpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 7 +-- files/mygui/openmw_settings_window.layout | 40 ++++++--------- files/settings-default.cfg | 2 - 6 files changed, 43 insertions(+), 73 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index cdfe4d2b6..294921cdd 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -109,6 +109,7 @@ namespace MWGui getWidget(mReflectActorsButton, "ReflectActorsButton"); getWidget(mReflectTerrainButton, "ReflectTerrainButton"); getWidget(mShadersButton, "ShadersButton"); + getWidget(mShaderModeButton, "ShaderModeButton"); getWidget(mShadowsEnabledButton, "ShadowsEnabledButton"); getWidget(mShadowsLargeDistance, "ShadowsLargeDistance"); getWidget(mShadowsTextureSize, "ShadowsTextureSize"); @@ -122,7 +123,6 @@ namespace MWGui getWidget(mInvertYButton, "InvertYButton"); getWidget(mUISensitivitySlider, "UISensitivitySlider"); getWidget(mCameraSensitivitySlider, "CameraSensitivitySlider"); - getWidget(mGammaSlider, "GammaSlider"); mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -130,6 +130,7 @@ namespace MWGui mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mUnderwaterButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mShadersButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadersToggled); + mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mWaterShaderButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectObjectsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -144,7 +145,6 @@ namespace MWGui mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mAnisotropySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mGammaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mShadowsEnabledButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mShadowsLargeDistance->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -202,14 +202,6 @@ namespace MWGui getWidget(fovText, "FovText"); fovText->setCaption("Field of View (" + boost::lexical_cast(int(Settings::Manager::getFloat("field of view", "General"))) + ")"); - float gammaVal = (Settings::Manager::getFloat("gamma", "Video")-0.1f)/(3.f-0.1f); - mGammaSlider->setScrollPosition(gammaVal * (mGammaSlider->getScrollRange()-1)); - MyGUI::TextBox* gammaText; - getWidget(gammaText, "GammaText"); - std::stringstream gamma; - gamma << std::setprecision (2) << Settings::Manager::getFloat("gamma", "Video"); - gammaText->setCaption("Gamma (" + gamma.str() + ")"); - float anisotropyVal = Settings::Manager::getInt("anisotropy", "General") / 16.0; mAnisotropySlider->setScrollPosition(anisotropyVal * (mAnisotropySlider->getScrollRange()-1)); std::string tf = Settings::Manager::getString("texture filtering", "General"); @@ -250,14 +242,8 @@ namespace MWGui mInvertYButton->setCaptionWithReplacing(Settings::Manager::getBool("invert y axis", "Input") ? "#{sOn}" : "#{sOff}"); - std::string shaders; - if (!Settings::Manager::getBool("shaders", "Objects")) - shaders = "off"; - else - { - shaders = Settings::Manager::getString("shader mode", "General"); - } - mShadersButton->setCaption (shaders); + mShadersButton->setCaption (Settings::Manager::getBool("shaders", "Objects") ? "on" : "off"); + mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); if (!MWRender::RenderingManager::waterShaderSupported()) { @@ -267,7 +253,7 @@ namespace MWGui mReflectTerrainButton->setEnabled(false); } - if (shaders == "off") + if (!Settings::Manager::getBool("shaders", "Objects")) { mUnderwaterButton->setEnabled (false); mShadowsEnabledButton->setEnabled(false); @@ -424,19 +410,31 @@ namespace MWGui } } + void SettingsWindow::onShaderModeToggled(MyGUI::Widget* _sender) + { + std::string val = static_cast(_sender)->getCaption(); + if (val == "cg") + { + val = hlslGlsl(); + } + else + val = "cg"; + + static_cast(_sender)->setCaption(val); + + Settings::Manager::setString("shader mode", "General", val); + + apply(); + } + void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) { std::string val = static_cast(_sender)->getCaption(); if (val == "off") - { - val = hlslGlsl(); - } - else if (val == hlslGlsl()) - val = "cg"; + val = "on"; else val = "off"; - - static_cast(_sender)->setCaption(val); + static_cast(_sender)->setCaption (val); if (val == "off") { @@ -461,7 +459,6 @@ namespace MWGui else { Settings::Manager::setBool("shaders", "Objects", true); - Settings::Manager::setString("shader mode", "General", val); // re-enable if (MWRender::RenderingManager::waterShaderSupported()) @@ -521,15 +518,6 @@ namespace MWGui fovText->setCaption("Field of View (" + boost::lexical_cast(int((1-val) * sFovMin + val * sFovMax)) + ")"); Settings::Manager::setFloat("field of view", "General", (1-val) * sFovMin + val * sFovMax); } - else if (scroller == mGammaSlider) - { - Settings::Manager::setFloat("gamma", "Video", (1-val) * 0.1f + val * 3.f); - MyGUI::TextBox* gammaText; - getWidget(gammaText, "GammaText"); - std::stringstream gamma; - gamma << std::setprecision (2) << Settings::Manager::getFloat("gamma", "Video"); - gammaText->setCaption("Gamma (" + gamma.str() + ")"); - } else if (scroller == mAnisotropySlider) { mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(int(val*16)) + ")"); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index e878d0abe..8ca3ad758 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -40,7 +40,6 @@ namespace MWGui MyGUI::Button* mFPSButton; MyGUI::ScrollBar* mViewDistanceSlider; MyGUI::ScrollBar* mFOVSlider; - MyGUI::ScrollBar* mGammaSlider; MyGUI::ScrollBar* mAnisotropySlider; MyGUI::Button* mTextureFilteringButton; MyGUI::TextBox* mAnisotropyLabel; @@ -50,6 +49,7 @@ namespace MWGui MyGUI::Button* mReflectActorsButton; MyGUI::Button* mReflectTerrainButton; MyGUI::Button* mShadersButton; + MyGUI::Button* mShaderModeButton; MyGUI::Button* mUnderwaterButton; MyGUI::Button* mShadowsEnabledButton; @@ -84,6 +84,7 @@ namespace MWGui void onResolutionCancel(); void onShadersToggled(MyGUI::Widget* _sender); + void onShaderModeToggled(MyGUI::Widget* _sender); void onShadowTextureSize(MyGUI::Widget* _sender); void onRebindAction(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8ec495550..a1f915ac9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -177,8 +177,7 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); - // The HUD is always on - mHud->setVisible(true); + mHud->setVisible(mHudEnabled); mCharGen = new CharacterCreation(this); @@ -1001,7 +1000,6 @@ void WindowManager::notifyInputActionBound () allowMouse(); } - void WindowManager::showCrosshair (bool show) { mHud->setCrosshairVisible (show && mCrosshairEnabled); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ae7d6612b..ff26b087c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -134,7 +134,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty(new sh::FloatValue( - Settings::Manager::getFloat ("gamma", "Video")))); + 1.f))); applyCompositors(); @@ -782,11 +782,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); mObjects.rebuildStaticGeometry (); } - else if (it->second == "gamma" && it->first == "Video") - { - sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty(new sh::FloatValue( - Settings::Manager::getFloat ("gamma", "Video")))); - } else if (it->second == "shader mode" && it->first == "General") { sh::Language lang; diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2f9b5a67f..f03305ae7 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -157,53 +157,43 @@ - + - + - + - - - - - - - - + - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 26546c2b1..31aa60c42 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -28,8 +28,6 @@ vsync = false # PBuffer, FBO, Copy opengl rtt mode = FBO -gamma = 2.2 - [GUI] # 1 is fully opaque menu transparency = 0.84 From 31e6d28b19f1afedcdefb0caa6a5664e413c72cf Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jan 2013 06:37:43 +0100 Subject: [PATCH 345/916] Close NIF file resource after loading it into memory --- components/nif/nif_file.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 07d34b9ea..3db34e0cc 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -177,6 +177,8 @@ NIFFile::NIFFile(const std::string &name, psudo_private_modifier) { inp = Ogre::ResourceGroupManager::getSingleton().openResource(name); parse(); + // Make sure to close the file after it was loaded into memory + inp.setNull(); } NIFFile::~NIFFile() From 2c3719a6f5f2a4110e412781de0f4b955e1b2441 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jan 2013 07:02:12 +0100 Subject: [PATCH 346/916] Disabling PSSM feature to make sure we can fit the max. amount of terrain textures in Morrowind.esm in a single pass. --- apps/openmw/mwgui/settingswindow.cpp | 5 ++++- apps/openmw/mwrender/shadows.cpp | 4 ++-- apps/openmw/mwrender/terrainmaterial.cpp | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 294921cdd..c5c6eada2 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -225,7 +225,10 @@ namespace MWGui mUnderwaterButton->setCaptionWithReplacing(Settings::Manager::getBool("underwater effect", "Water") ? "#{sOn}" : "#{sOff}"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); - mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); + //mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); + mShadowsLargeDistance->setCaptionWithReplacing("#{sOff}"); + mShadowsLargeDistance->setEnabled (false); + mShadowsEnabledButton->setCaptionWithReplacing(Settings::Manager::getBool("enabled", "Shadows") ? "#{sOn}" : "#{sOff}"); mActorShadows->setCaptionWithReplacing(Settings::Manager::getBool("actor shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); mStaticsShadows->setCaptionWithReplacing(Settings::Manager::getBool("statics shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 3d9f13243..808c8b5d9 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -33,8 +33,8 @@ void Shadows::recreate() // Split shadow maps are currently disabled because the terrain cannot cope with them // (Too many texture units) Solution would be a multi-pass terrain material - bool split = Settings::Manager::getBool("split", "Shadows"); - //const bool split = false; + //bool split = Settings::Manager::getBool("split", "Shadows"); + const bool split = false; sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false"); diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 5ef9fe58f..d5e531f86 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -153,7 +153,8 @@ namespace MWRender --freeTextureUnits; // colourmap --freeTextureUnits; - freeTextureUnits -= 3; // shadow PSSM + // shadow + --freeTextureUnits; --freeTextureUnits; // caustics From e4f140841e2e9eacb25c671cbe03c61938b1219c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 12 Jan 2013 08:23:15 +0100 Subject: [PATCH 347/916] Make OpenMW work with Ogre 1.9 --- apps/launcher/graphicspage.cpp | 1 + apps/openmw/mwrender/localmap.cpp | 1 - apps/openmw/mwrender/shadows.cpp | 5 ++--- apps/openmw/mwrender/terrainmaterial.hpp | 1 + apps/openmw/mwrender/water.cpp | 3 --- components/bsa/bsa_archive.cpp | 5 +++++ libs/openengine/ogre/renderer.cpp | 1 + 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2c4f3430c..cc4cbfe7d 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -122,6 +122,7 @@ bool GraphicsPage::setupOgre() pluginDir = absPluginPath.string(); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mOgre); + Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mOgre); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mOgre); #ifdef ENABLE_PLUGIN_GL diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d878cb86e..b34942d28 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,6 +1,5 @@ #include "localmap.hpp" -#include #include #include diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 808c8b5d9..595a82294 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -9,9 +9,6 @@ #include #include -#include -#include - #include #include "renderconst.hpp" @@ -125,6 +122,7 @@ void Shadows::recreate() // -------------------------------------------------------------------------------------------------------------------- // --------------------------- Debug overlays to display the content of shadow maps ----------------------------------- // -------------------------------------------------------------------------------------------------------------------- + /* if (Settings::Manager::getBool("debug", "Shadows")) { OverlayManager& mgr = OverlayManager::getSingleton(); @@ -181,6 +179,7 @@ void Shadows::recreate() if ((overlay = mgr.getByName("DebugOverlay"))) mgr.destroy(overlay); } + */ } PSSMShadowCameraSetup* Shadows::getPSSMSetup() diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index 3e31b2a58..fe1214cf5 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -67,6 +67,7 @@ namespace MWRender void setGlobalColourMapEnabled(bool enabled); void setGlobalColourMap (Ogre::Terrain* terrain, const std::string& name); + virtual void setLightmapEnabled(bool) {} private: sh::MaterialInstance* mMaterial; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index a16a23b26..04a126367 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -8,9 +8,6 @@ #include #include #include -#include -#include -#include #include "sky.hpp" #include "renderingmanager.hpp" diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 9913fb8aa..3bff93baa 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -403,6 +403,11 @@ public: return new BSAArchive(name); } + virtual Archive* createInstance(const String& name, bool readOnly) + { + return new BSAArchive(name); + } + void destroyInstance( Archive* arch) { delete arch; } }; diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 3cdb00518..ed5cc9b43 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -192,6 +192,7 @@ void OgreRenderer::configure(const std::string &logPath, pluginDir = absPluginPath.string(); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot); + Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); From f4ee8e26429fe8b27247b47ce88994e9e5c3937d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 12 Jan 2013 13:10:20 +0100 Subject: [PATCH 348/916] Issue #479: Added additional magnitude parameter to known spells --- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 12 ++++++------ apps/openmw/mwgui/spellcreationdialog.cpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwmechanics/spells.cpp | 24 +++++++++++------------ apps/openmw/mwmechanics/spells.hpp | 10 +++++----- apps/openmw/mwscript/statsextensions.cpp | 6 +++--- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 02512425d..6d51420f0 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -440,7 +440,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - spellList.push_back(*it); + spellList.push_back (it->first); } const MWWorld::ESMStore &esmStore = diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index a41f401a5..11f090494 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -98,19 +98,19 @@ namespace MWGui MWMechanics::Spells& playerSpells = MWWorld::Class::get (player).getCreatureStats (player).getSpells(); MWMechanics::Spells& merchantSpells = MWWorld::Class::get (actor).getCreatureStats (actor).getSpells(); - + for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) { const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find (*iter); - + MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); + if (spell->mData.mType!=ESM::Spell::ST_Spell) continue; // don't try to sell diseases, curses or powers - + if (std::find (playerSpells.begin(), playerSpells.end(), *iter)!=playerSpells.end()) continue; // we have that spell already - - addSpell (*iter); + + addSpell (iter->first); } updateLabels(); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 69d69519f..839586452 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -436,7 +436,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(*it); + MWBase::Environment::get().getWorld()->getStore().get().find (it->first); // only normal spells count if (spell->mData.mType != ESM::Spell::ST_Spell) diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d62b23de4..47e1d739a 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -139,7 +139,7 @@ namespace MWGui for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { - spellList.push_back(*it); + spellList.push_back (it->first); } const MWWorld::ESMStore &esmStore = diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index ef084f479..32acca2f0 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -29,13 +29,13 @@ namespace MWMechanics void Spells::add (const std::string& spellId) { - if (std::find (mSpells.begin(), mSpells.end(), spellId)==mSpells.end()) - mSpells.push_back (spellId); + if (mSpells.find (spellId)==mSpells.end()) + mSpells.insert (std::make_pair (spellId, -1)); } void Spells::remove (const std::string& spellId) { - TContainer::iterator iter = std::find (mSpells.begin(), mSpells.end(), spellId); + TContainer::iterator iter = mSpells.find (spellId); if (iter!=mSpells.end()) mSpells.erase (iter); @@ -51,7 +51,7 @@ namespace MWMechanics for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (*iter); + MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); if (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse) @@ -75,18 +75,18 @@ namespace MWMechanics { return mSelectedSpell; } - + bool Spells::hasCommonDisease() const { for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (*iter); - + MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); + if (spell->mData.mFlags & ESM::Spell::ST_Disease) return true; } - + return false; } @@ -95,12 +95,12 @@ namespace MWMechanics for (TIterator iter = mSpells.begin(); iter!=mSpells.end(); ++iter) { const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find (*iter); - + MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); + if (spell->mData.mFlags & ESM::Spell::ST_Blight) return true; } - - return false; + + return false; } } diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index 12308661b..b4d058896 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWMECHANICS_SPELLS_H #define GAME_MWMECHANICS_SPELLS_H -#include +#include #include namespace ESM @@ -21,12 +21,12 @@ namespace MWMechanics { public: - typedef std::vector TContainer; + typedef std::map TContainer; // ID, magnitude typedef TContainer::const_iterator TIterator; private: - std::vector mSpells; + TContainer mSpells; std::string mSelectedSpell; void addSpell (const ESM::Spell *, MagicEffects& effects) const; @@ -55,10 +55,10 @@ namespace MWMechanics const std::string getSelectedSpell() const; ///< May return an empty string. - + bool hasCommonDisease() const; - bool hasBlightDisease() const; + bool hasBlightDisease() const; }; } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 31ea7518b..530d44c9d 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -485,7 +485,7 @@ namespace MWScript for (MWMechanics::Spells::TIterator iter ( MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().begin()); iter!=MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().end(); ++iter) - if (*iter==id) + if (iter->first==id) { value = 1; break; @@ -1188,7 +1188,7 @@ namespace MWScript extensions.registerFunction ("getpccrimelevel", 'f', "", opcodeGetPCCrimeLevel); extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel); extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel); - + extensions.registerInstruction ("addspell", "c", opcodeAddSpell, opcodeAddSpellExplicit); extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell, opcodeRemoveSpellExplicit); @@ -1286,7 +1286,7 @@ namespace MWScript interpreter.installSegment5 (opcodeGetPCCrimeLevel, new OpGetPCCrimeLevel); interpreter.installSegment5 (opcodeSetPCCrimeLevel, new OpSetPCCrimeLevel); interpreter.installSegment5 (opcodeModPCCrimeLevel, new OpModPCCrimeLevel); - + interpreter.installSegment5 (opcodeAddSpell, new OpAddSpell); interpreter.installSegment5 (opcodeAddSpellExplicit, new OpAddSpell); interpreter.installSegment5 (opcodeRemoveSpell, new OpRemoveSpell); From 35d17fdaf65b37b48fc92edcda0d6334cd1c20b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 07:12:12 -0800 Subject: [PATCH 349/916] Associate a character controller with each MWWorld::Ptr --- apps/openmw/mwmechanics/actors.cpp | 115 ++++++++++++-------------- apps/openmw/mwmechanics/actors.hpp | 9 +- apps/openmw/mwmechanics/character.hpp | 5 ++ 3 files changed, 64 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d541baea9..a7e8f0db1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,30 +166,28 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors.insert (ptr); + mActors[ptr] = CharacterController(); else MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } void Actors::removeActor (const MWWorld::Ptr& ptr) { - std::set::iterator iter = mActors.find (ptr); - - if (iter!=mActors.end()) - mActors.erase (iter); + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + mActors.erase(iter); } void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) { - std::set::iterator iter = mActors.begin(); - - while (iter!=mActors.end()) - if (iter->getCell()==cellStore) - { - mActors.erase (iter++); - } + PtrControllerMap::iterator iter = mActors.begin(); + while(iter != mActors.end()) + { + if(iter->first.getCell()==cellStore) + mActors.erase(iter++); else ++iter; + } } void Actors::update (std::vector >& movement, float duration, @@ -201,79 +199,72 @@ namespace MWMechanics { float totalDuration = mDuration; mDuration = 0; - - std::set::iterator iter (mActors.begin()); - while (iter!=mActors.end()) + PtrControllerMap::iterator iter(mActors.begin()); + while(iter != mActors.end()) { - if (!MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead()) + if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - updateActor (*iter, totalDuration); + updateActor(iter->first, totalDuration); + if(iter->first.getTypeName() == typeid(ESM::NPC).name()) + updateNpc(iter->first, totalDuration, paused); - if (iter->getTypeName()==typeid (ESM::NPC).name()) - updateNpc (*iter, totalDuration, paused); - } - - if (MWWorld::Class::get (*iter).getCreatureStats (*iter).isDead()) - { - // workaround: always keep player alive for now - // \todo remove workaround, once player death can be handled - if (iter->getRefData().getHandle()=="player") + if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - MWMechanics::DynamicStat stat ( - MWWorld::Class::get (*iter).getCreatureStats (*iter).getHealth()); - - if (stat.getModified()<1) - { - stat.setModified (1, 0); - MWWorld::Class::get (*iter).getCreatureStats (*iter).setHealth (stat); - } - - MWWorld::Class::get (*iter).getCreatureStats (*iter).resurrect(); - ++iter; + iter++; continue; } - - ++mDeathCount[MWWorld::Class::get (*iter).getId (*iter)]; - - MWBase::Environment::get().getWorld()->playAnimationGroup (*iter, "death1", 0); - - if (MWWorld::Class::get (*iter).isEssential (*iter)) - MWBase::Environment::get().getWindowManager()->messageBox ( - "#{sKilledEssential}", std::vector()); - - mActors.erase (iter++); } - else + + // workaround: always keep player alive for now + // \todo remove workaround, once player death can be handled + if(iter->first.getRefData().getHandle()=="player") + { + MWMechanics::DynamicStat stat ( + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).getHealth()); + + if (stat.getModified()<1) + { + stat.setModified (1, 0); + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).setHealth(stat); + } + + MWWorld::Class::get(iter->first).getCreatureStats(iter->first).resurrect(); ++iter; + continue; + } + + ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + + MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); + + if(MWWorld::Class::get(iter->first).isEssential(iter->first)) + MWBase::Environment::get().getWindowManager()->messageBox( + "#{sKilledEssential}", std::vector()); + + mActors.erase(iter++); } } - for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); - ++iter) + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 vector = MWWorld::Class::get (*iter).getMovementVector (*iter); - - if (vector!=Ogre::Vector3::ZERO) - movement.push_back (std::make_pair (iter->getRefData().getHandle(), vector)); + Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + if(vector!=Ogre::Vector3::ZERO) + movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } } void Actors::restoreDynamicStats() { - for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter) - { - calculateRestoration (*iter, 3600); - } + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + calculateRestoration(iter->first, 3600); } int Actors::countDeaths (const std::string& id) const { - std::map::const_iterator iter = mDeathCount.find (id); - - if (iter!=mDeathCount.end()) + std::map::const_iterator iter = mDeathCount.find(id); + if(iter != mDeathCount.end()) return iter->second; - return 0; } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 79ae16fc3..f1e5ab437 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -6,6 +6,8 @@ #include #include +#include "character.hpp" + namespace Ogre { class Vector3; @@ -21,9 +23,10 @@ namespace MWMechanics { class Actors { - std::set mActors; - float mDuration; - std::map mDeathCount; + typedef std::map PtrControllerMap; + PtrControllerMap mActors; + float mDuration; + std::map mDeathCount; void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cab269112..c7638970d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -4,6 +4,11 @@ namespace MWMechanics { +class CharacterController +{ + +}; + } #endif /* GAME_MWMECHANICS_CHARACTER_HPP */ From 4890d901a28ff26c93fcc9a7c16f3ee2d9751718 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 08:49:08 -0800 Subject: [PATCH 350/916] Store an MWWorld::Ptr in the character controller --- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a7e8f0db1..aa5119dba 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,7 +166,7 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors[ptr] = CharacterController(); + mActors.insert(std::make_pair(ptr, CharacterController(ptr))); else MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c7638970d..1b5320375 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -1,12 +1,19 @@ #ifndef GAME_MWMECHANICS_CHARACTER_HPP #define GAME_MWMECHANICS_CHARACTER_HPP +#include "../mwworld/ptr.hpp" + namespace MWMechanics { class CharacterController { + MWWorld::Ptr mPtr; +public: + CharacterController(const MWWorld::Ptr &ptr) + : mPtr(ptr) + { } }; } From 94b24f07e1581fbb0f3310a77537e274887f4844 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 12 Jan 2013 10:10:27 -0800 Subject: [PATCH 351/916] Keep track of the state in the character controller, and don't remove dead actors from the map --- apps/openmw/mwmechanics/actors.cpp | 21 ++++++++++++++++----- apps/openmw/mwmechanics/character.hpp | 17 +++++++++++++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index aa5119dba..4eae6e213 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -165,10 +165,13 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { - if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr))); + if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) + mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Idle))); else + { + mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Dead))); MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); + } } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -205,6 +208,9 @@ namespace MWMechanics { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { + if(iter->second.getState() == CharState_Dead) + iter->second.setState(CharState_Idle); + updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) updateNpc(iter->first, totalDuration, paused); @@ -234,15 +240,20 @@ namespace MWMechanics continue; } - ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + if(iter->second.getState() == CharState_Dead) + { + iter++; + continue; + } + iter->second.setState(CharState_Dead); MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); + ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; + if(MWWorld::Class::get(iter->first).isEssential(iter->first)) MWBase::Environment::get().getWindowManager()->messageBox( "#{sKilledEssential}", std::vector()); - - mActors.erase(iter++); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1b5320375..206f6e737 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -6,14 +6,27 @@ namespace MWMechanics { +enum CharacterState { + CharState_Idle, + CharState_Dead +}; + class CharacterController { MWWorld::Ptr mPtr; + CharacterState mState; + public: - CharacterController(const MWWorld::Ptr &ptr) - : mPtr(ptr) + CharacterController(const MWWorld::Ptr &ptr, CharacterState state) + : mPtr(ptr), mState(state) { } + + CharacterState getState() const + { return mState; } + + void setState(CharacterState state) + { mState = state; } }; } From d4ca954d47c0e19ee767efd2f263183ddd0b2839 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sat, 12 Jan 2013 18:31:57 +0000 Subject: [PATCH 352/916] scripts on items in containers added to script list on cell change --- apps/openmw/mwworld/localscripts.cpp | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index a821ad486..9c9131008 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -3,6 +3,10 @@ #include "esmstore.hpp" #include "cellstore.hpp" +#include "class.hpp" +#include "containerstore.hpp" + + namespace { template @@ -19,6 +23,32 @@ namespace } } } + + // Adds scripts for items in containers (containers/npcs/creatures) + template + void listCellScriptsCont (MWWorld::LocalScripts& localScripts, + MWWorld::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) + { + for (typename MWWorld::CellRefList::List::iterator iter ( + cellRefList.mList.begin()); + iter!=cellRefList.mList.end(); ++iter) + { + + MWWorld::Ptr containerPtr (&*iter, cell); + + MWWorld::ContainerStore& container = MWWorld::Class::get(containerPtr).getContainerStore(containerPtr); + for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) + { + std::string script = MWWorld::Class::get(*it3).getScript(*it3); + if(script != "") + { + MWWorld::Ptr item = *it3; + item.mCell = cell; + localScripts.add (script, item); + } + } + } + } } MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} @@ -78,13 +108,16 @@ void MWWorld::LocalScripts::addCell (Ptr::CellStore *cell) listCellScripts (*this, cell->mBooks, cell); listCellScripts (*this, cell->mClothes, cell); listCellScripts (*this, cell->mContainers, cell); + listCellScriptsCont (*this, cell->mContainers, cell); listCellScripts (*this, cell->mCreatures, cell); + listCellScriptsCont (*this, cell->mCreatures, cell); listCellScripts (*this, cell->mDoors, cell); listCellScripts (*this, cell->mIngreds, cell); listCellScripts (*this, cell->mLights, cell); listCellScripts (*this, cell->mLockpicks, cell); listCellScripts (*this, cell->mMiscItems, cell); listCellScripts (*this, cell->mNpcs, cell); + listCellScriptsCont (*this, cell->mNpcs, cell); listCellScripts (*this, cell->mProbes, cell); listCellScripts (*this, cell->mRepairs, cell); listCellScripts (*this, cell->mWeapons, cell); From 654cd3ab9bef7aad11a8c5e3a55a26d4100065cc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 13 Jan 2013 14:52:55 +0100 Subject: [PATCH 353/916] Issue #479: Use magnitude specified when adding disease --- apps/openmw/mwmechanics/magiceffects.cpp | 10 +++++++--- apps/openmw/mwmechanics/magiceffects.hpp | 3 ++- apps/openmw/mwmechanics/spells.cpp | 13 +++++-------- apps/openmw/mwmechanics/spells.hpp | 4 +--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/magiceffects.cpp b/apps/openmw/mwmechanics/magiceffects.cpp index 94363cb79..1a7b34817 100644 --- a/apps/openmw/mwmechanics/magiceffects.cpp +++ b/apps/openmw/mwmechanics/magiceffects.cpp @@ -68,7 +68,7 @@ namespace MWMechanics } } - void MagicEffects::add (const ESM::EffectList& list) + void MagicEffects::add (const ESM::EffectList& list, float magnitude) { for (std::vector::const_iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) @@ -78,9 +78,13 @@ namespace MWMechanics if (iter->mMagnMin>=iter->mMagnMax) param.mMagnitude = iter->mMagnMin; else + { + if (magnitude==-1) + magnitude = static_cast (std::rand()) / RAND_MAX; + param.mMagnitude = static_cast ( - (iter->mMagnMax-iter->mMagnMin+1)* - (static_cast (std::rand()) / RAND_MAX) + iter->mMagnMin); + (iter->mMagnMax-iter->mMagnMin+1)*magnitude + iter->mMagnMin); + } add (*iter, param); } diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index 2f61d7eeb..b80b5a863 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -67,7 +67,8 @@ namespace MWMechanics void add (const EffectKey& key, const EffectParam& param); - void add (const ESM::EffectList& list); + void add (const ESM::EffectList& list, float magnitude = -1); + ///< \param magnitude normalised magnitude (-1: random) MagicEffects& operator+= (const MagicEffects& effects); diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 32acca2f0..e2da7cdc8 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,22 +1,19 @@ #include "spells.hpp" -#include "../mwworld/esmstore.hpp" +#include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/esmstore.hpp" + #include "magiceffects.hpp" namespace MWMechanics { - void Spells::addSpell (const ESM::Spell *spell, MagicEffects& effects) const - { - effects.add (spell->mEffects); - } - Spells::TIterator Spells::begin() const { return mSpells.begin(); @@ -30,7 +27,7 @@ namespace MWMechanics void Spells::add (const std::string& spellId) { if (mSpells.find (spellId)==mSpells.end()) - mSpells.insert (std::make_pair (spellId, -1)); + mSpells.insert (std::make_pair (spellId, static_cast (std::rand()) / RAND_MAX)); } void Spells::remove (const std::string& spellId) @@ -55,7 +52,7 @@ namespace MWMechanics if (spell->mData.mType==ESM::Spell::ST_Ability || spell->mData.mType==ESM::Spell::ST_Blight || spell->mData.mType==ESM::Spell::ST_Disease || spell->mData.mType==ESM::Spell::ST_Curse) - addSpell (spell, effects); + effects.add (spell->mEffects, iter->second); } return effects; diff --git a/apps/openmw/mwmechanics/spells.hpp b/apps/openmw/mwmechanics/spells.hpp index b4d058896..e00ac259f 100644 --- a/apps/openmw/mwmechanics/spells.hpp +++ b/apps/openmw/mwmechanics/spells.hpp @@ -21,7 +21,7 @@ namespace MWMechanics { public: - typedef std::map TContainer; // ID, magnitude + typedef std::map TContainer; // ID, normalised magnitude typedef TContainer::const_iterator TIterator; private: @@ -29,8 +29,6 @@ namespace MWMechanics TContainer mSpells; std::string mSelectedSpell; - void addSpell (const ESM::Spell *, MagicEffects& effects) const; - public: TIterator begin() const; From 660d73fd888f185b31bff036298a1d405060944f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Jan 2013 06:56:58 -0800 Subject: [PATCH 354/916] Store the NIF index in the Record object --- components/nif/nif_file.cpp | 11 +++++------ components/nif/record.hpp | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 3db34e0cc..6b024ab68 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -39,9 +39,8 @@ //#include //#include -using namespace std; -using namespace Nif; -using namespace Misc; +namespace Nif +{ class NIFFile::LoadedCache { @@ -311,6 +310,7 @@ void NIFFile::parse() assert(r != NULL); assert(r->recType != RC_MISSING); r->recName = rec; + r->recIndex = i; records[i] = r; r->read(this); @@ -329,9 +329,6 @@ void NIFFile::parse() tree, but for the moment we ignore it. */ - // TODO: Set up kf file here first, if applicable. It needs its own - // code to link it up with the main NIF structure. - // Once parsing is done, do post-processing. for(int i=0; ipost(this); @@ -375,3 +372,5 @@ Ogre::Matrix4 Node::getWorldTransform() const return parent->getWorldTransform() * getLocalTransform(); return getLocalTransform(); } + +} diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 5c4141fa9..d5f65e83a 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -91,8 +91,9 @@ struct Record // Record type and type name int recType; std::string recName; + size_t recIndex; - Record() : recType(RC_MISSING) {} + Record() : recType(RC_MISSING), recIndex(~(size_t)0) {} /// Parses the record from file virtual void read(NIFFile *nif) = 0; From b23fcb260cc75aebd5f6f27485320e14e78c3d1c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 13 Jan 2013 08:00:04 -0800 Subject: [PATCH 355/916] Use the record index for finding the NiTriShape instead of the name --- components/nif/nif_file.cpp | 6 ++--- components/nif/nif_file.hpp | 2 +- components/nifogre/ogre_nif_loader.cpp | 32 +++++++++++++++----------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 6b024ab68..e6d3182ed 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -206,7 +206,7 @@ void NIFFile::parse() fail("Unsupported NIF version"); // Number of records - int recNum = getInt(); + size_t recNum = getInt(); records.resize(recNum); /* The format for 10.0.1.0 seems to be a bit different. After the @@ -218,7 +218,7 @@ void NIFFile::parse() we do not support or plan to support other versions yet. */ - for(int i=0;ipost(this); } diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index ded3f7362..e8884cd4d 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -146,7 +146,7 @@ public: } /// Number of records - int numRecords() { return records.size(); } + size_t numRecords() { return records.size(); } /************************************************* Parser functions diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 777deabdf..dfbc93ee9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -695,9 +695,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { std::string mName; std::string mGroup; - std::string mShapeName; - std::string mMaterialName; + size_t mShapeIndex; std::string mSkelName; + std::string mMaterialName; + std::string mShapeName; void warn(const std::string &msg) { @@ -805,7 +806,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::VertexDeclaration *decl; int nextBuf = 0; - Ogre::SubMesh *sub = mesh->createSubMesh(shape->name); + Ogre::SubMesh *sub = ((mShapeName.length() > 0) ? mesh->createSubMesh(mShapeName) : + mesh->createSubMesh()); // Add vertices sub->useSharedVertices = false; @@ -912,13 +914,13 @@ class NIFMeshLoader : Ogre::ManualResourceLoader bool findTriShape(Ogre::Mesh *mesh, Nif::Node const *node) { - if(node->recType == Nif::RC_NiTriShape && mShapeName == node->name) + if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node)); + handleNiTriShape(mesh, dynamic_cast(node)); return true; } - Nif::NiNode const *ninode = dynamic_cast(node); + const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { Nif::NodeList const &children = ninode->children; @@ -942,7 +944,7 @@ public: NIFMeshLoader() { } NIFMeshLoader(const std::string &name, const std::string &group, const std::string skelName) - : mName(name), mGroup(group), mSkelName(skelName) + : mName(name), mGroup(group), mShapeIndex(~(size_t)0), mSkelName(skelName) { } virtual void loadResource(Ogre::Resource *resource) @@ -950,15 +952,14 @@ public: Ogre::Mesh *mesh = dynamic_cast(resource); assert(mesh && "Attempting to load a mesh into a non-mesh resource!"); - if(!mShapeName.length()) + Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); + if(mShapeIndex >= nif->numRecords()) { - if(mSkelName.length() > 0) - mesh->setSkeletonName(mSkelName); + mesh->setSkeletonName(mSkelName); return; } - Nif::NIFFile::ptr nif = Nif::NIFFile::create (mName); - Nif::Node const *node = dynamic_cast(nif->getRecord(0)); + Nif::Node const *node = dynamic_cast(nif->getRecord(mShapeIndex)); findTriShape(mesh, node); } @@ -999,9 +1000,12 @@ public: if(node->recType == Nif::RC_NiTriShape) { const Nif::NiTriShape *shape = dynamic_cast(node); + mShapeName = shape->name; Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - std::string fullname = mName+"@shape="+shape->name; + std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); + if(mShapeName.length() > 0) + fullname += "@shape="+mShapeName; if(mSkelName.length() > 0 && mName != mSkelName) fullname += "@skel="+mSkelName; @@ -1013,7 +1017,7 @@ public: *loader = *this; if(!(flags&0x01)) // Not hidden { - loader->mShapeName = shape->name; + loader->mShapeIndex = shape->recIndex; loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); } From c138e00aa250b1cca9cd8484b085df6830218685 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 13 Jan 2013 17:05:12 +0000 Subject: [PATCH 356/916] objects scripts are now stopped when they are removed from a container --- apps/openmw/mwbase/world.hpp | 4 ++++ apps/openmw/mwworld/localscripts.cpp | 14 ++++++++++++++ apps/openmw/mwworld/localscripts.hpp | 3 +++ apps/openmw/mwworld/refdata.cpp | 6 ++++++ apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 3 +++ 6 files changed, 35 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a576912c0..2ce7ce2c7 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -45,6 +45,7 @@ namespace MWWorld class Ptr; class TimeStamp; class ESMStore; + class RefData; } namespace MWBase @@ -138,6 +139,9 @@ namespace MWBase virtual std::string getCurrentCellName() const = 0; + virtual void removeRefScript (MWWorld::RefData *ref) = 0; + //< Remove the script attached to ref from mLocalScripts + virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 9c9131008..2fa0d4086 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -146,6 +146,20 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell) } } +void MWWorld::LocalScripts::remove (RefData *ref) +{ + for (std::list >::iterator iter = mScripts.begin(); + iter!=mScripts.end(); ++iter) + if (&(iter->second.getRefData()) == ref) + { + if (iter==mIter) + ++mIter; + + mScripts.erase (iter); + break; + } +} + void MWWorld::LocalScripts::remove (const Ptr& ptr) { for (std::list >::iterator iter = mScripts.begin(); diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 028dcdeda..840243fff 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -10,6 +10,7 @@ namespace MWWorld { struct ESMStore; class CellStore; + class RefData; /// \brief List of active local scripts class LocalScripts @@ -47,6 +48,8 @@ namespace MWWorld void clearCell (CellStore *cell); ///< Remove all scripts belonging to \a cell. + + void remove (RefData *ref); void remove (const Ptr& ptr); ///< Remove script for given reference (ignored if reference does not have a scirpt listed). diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 5630bfd5c..4be287810 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -6,6 +6,9 @@ #include "customdata.hpp" #include "cellstore.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + namespace MWWorld { void RefData::copy (const RefData& refData) @@ -107,6 +110,9 @@ namespace MWWorld void RefData::setCount (int count) { + if(count == 0) + MWBase::Environment::get().getWorld()->removeRefScript(this); + mCount = count; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f49b4bf9b..716cd6e96 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -341,6 +341,11 @@ namespace MWWorld return name; } + void World::removeRefScript (MWWorld::RefData *ref) + { + mLocalScripts.remove (ref); + } + Ptr World::getPtr (const std::string& name, bool activeOnly) { // the player is always in an active cell. diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7e89c1d87..905e6fd96 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -172,6 +172,9 @@ namespace MWWorld virtual std::vector getGlobals () const; virtual std::string getCurrentCellName () const; + + virtual void removeRefScript (MWWorld::RefData *ref); + //< Remove the script attached to ref from mLocalScripts virtual Ptr getPtr (const std::string& name, bool activeOnly); ///< Return a pointer to a liveCellRef with the given name. From 6fc64e8a4e9d374040f29343029ec197f5323cdd Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 13 Jan 2013 19:49:56 +0000 Subject: [PATCH 357/916] scripts run for items added to containers, and scripted items in player inv handled correctly --- apps/openmw/mwworld/containerstore.cpp | 28 +++++++++++++++++++++++++- apps/openmw/mwworld/containerstore.hpp | 1 + apps/openmw/mwworld/localscripts.cpp | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index db4537daf..6884aa6c8 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -15,6 +15,8 @@ #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" +#include "localscripts.hpp" +#include "player.hpp" namespace { @@ -71,6 +73,30 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) } MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) +{ + MWWorld::ContainerStoreIterator it = realAdd(ptr); + MWWorld::Ptr item = *it; + + std::string script = MWWorld::Class::get(item).getScript(item); + if(script != "") + { + CellStore *cell; + + Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + // Items in players inventory have cell set to 0, so their scripts will never be removed + if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) + cell = 0; + else + cell = player.getCell(); + + item.mCell = cell; + MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); + } + + return it; +} + +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::realAdd (const Ptr& ptr) { int type = getType(ptr); @@ -162,7 +188,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor } ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) - add (ref.getPtr()); + realAdd (ref.getPtr()); } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 1297fc53c..e274ee130 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -52,6 +52,7 @@ namespace MWWorld int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; + ContainerStoreIterator realAdd (const Ptr& ptr); public: diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 2fa0d4086..5ec5ca9b5 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -134,7 +134,7 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell) while (iter!=mScripts.end()) { - if (iter->second.getCell()==cell) + if (iter->second.mCell==cell) { if (iter==mIter) ++mIter; From aa514a53d998462695256aa121e77df0a03cc67e Mon Sep 17 00:00:00 2001 From: lazydev Date: Tue, 15 Jan 2013 02:22:14 +0400 Subject: [PATCH 358/916] Console font change to provide possibility to show cyrillic symbols --- Bitstream Vera License.txt | 123 ------------------------------ Dejavu_lgc_font_license.txt | 99 ++++++++++++++++++++++++ credits.txt | 4 +- files/mygui/CMakeLists.txt | 2 +- files/mygui/DejaVuLGCSansMono.ttf | Bin 0 -> 285304 bytes files/mygui/VeraMono.ttf | Bin 49224 -> 0 bytes files/mygui/openmw_font.xml | 2 +- 7 files changed, 103 insertions(+), 127 deletions(-) delete mode 100644 Bitstream Vera License.txt create mode 100644 Dejavu_lgc_font_license.txt create mode 100644 files/mygui/DejaVuLGCSansMono.ttf delete mode 100644 files/mygui/VeraMono.ttf diff --git a/Bitstream Vera License.txt b/Bitstream Vera License.txt deleted file mode 100644 index 2b37cc1df..000000000 --- a/Bitstream Vera License.txt +++ /dev/null @@ -1,123 +0,0 @@ -Bitstream Vera Fonts Copyright - -The fonts have a generous copyright, allowing derivative works (as -long as "Bitstream" or "Vera" are not in the names), and full -redistribution (so long as they are not *sold* by themselves). They -can be be bundled, redistributed and sold with any software. - -The fonts are distributed under the following copyright: - -Copyright -========= - -Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream -Vera is a trademark of Bitstream, Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the fonts accompanying this license ("Fonts") and associated -documentation files (the "Font Software"), to reproduce and distribute -the Font Software, including without limitation the rights to use, -copy, merge, publish, distribute, and/or sell copies of the Font -Software, and to permit persons to whom the Font Software is furnished -to do so, subject to the following conditions: - -The above copyright and trademark notices and this permission notice -shall be included in all copies of one or more of the Font Software -typefaces. - -The Font Software may be modified, altered, or added to, and in -particular the designs of glyphs or characters in the Fonts may be -modified and additional glyphs or characters may be added to the -Fonts, only if the fonts are renamed to names not containing either -the words "Bitstream" or the word "Vera". - -This License becomes null and void to the extent applicable to Fonts -or Font Software that has been modified and is distributed under the -"Bitstream Vera" names. - -The Font Software may be sold as part of a larger software package but -no copy of one or more of the Font Software typefaces may be sold by -itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL -BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, -OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT -SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. - -Except as contained in this notice, the names of Gnome, the Gnome -Foundation, and Bitstream Inc., shall not be used in advertising or -otherwise to promote the sale, use or other dealings in this Font -Software without prior written authorization from the Gnome Foundation -or Bitstream Inc., respectively. For further information, contact: -fonts at gnome dot org. - -Copyright FAQ -============= - - 1. I don't understand the resale restriction... What gives? - - Bitstream is giving away these fonts, but wishes to ensure its - competitors can't just drop the fonts as is into a font sale system - and sell them as is. It seems fair that if Bitstream can't make money - from the Bitstream Vera fonts, their competitors should not be able to - do so either. You can sell the fonts as part of any software package, - however. - - 2. I want to package these fonts separately for distribution and - sale as part of a larger software package or system. Can I do so? - - Yes. A RPM or Debian package is a "larger software package" to begin - with, and you aren't selling them independently by themselves. - See 1. above. - - 3. Are derivative works allowed? - Yes! - - 4. Can I change or add to the font(s)? - Yes, but you must change the name(s) of the font(s). - - 5. Under what terms are derivative works allowed? - - You must change the name(s) of the fonts. This is to ensure the - quality of the fonts, both to protect Bitstream and Gnome. We want to - ensure that if an application has opened a font specifically of these - names, it gets what it expects (though of course, using fontconfig, - substitutions could still could have occurred during font - opening). You must include the Bitstream copyright. Additional - copyrights can be added, as per copyright law. Happy Font Hacking! - - 6. If I have improvements for Bitstream Vera, is it possible they might get - adopted in future versions? - - Yes. The contract between the Gnome Foundation and Bitstream has - provisions for working with Bitstream to ensure quality additions to - the Bitstream Vera font family. Please contact us if you have such - additions. Note, that in general, we will want such additions for the - entire family, not just a single font, and that you'll have to keep - both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add - glyphs to the font, they must be stylistically in keeping with Vera's - design. Vera cannot become a "ransom note" font. Jim Lyles will be - providing a document describing the design elements used in Vera, as a - guide and aid for people interested in contributing to Vera. - - 7. I want to sell a software package that uses these fonts: Can I do so? - - Sure. Bundle the fonts with your software and sell your software - with the fonts. That is the intent of the copyright. - - 8. If applications have built the names "Bitstream Vera" into them, - can I override this somehow to use fonts of my choosing? - - This depends on exact details of the software. Most open source - systems and software (e.g., Gnome, KDE, etc.) are now converting to - use fontconfig (see www.fontconfig.org) to handle font configuration, - selection and substitution; it has provisions for overriding font - names and subsituting alternatives. An example is provided by the - supplied local.conf file, which chooses the family Bitstream Vera for - "sans", "serif" and "monospace". Other software (e.g., the XFree86 - core server) has other mechanisms for font substitution. diff --git a/Dejavu_lgc_font_license.txt b/Dejavu_lgc_font_license.txt new file mode 100644 index 000000000..254e2cc42 --- /dev/null +++ b/Dejavu_lgc_font_license.txt @@ -0,0 +1,99 @@ +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. +Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) + +Bitstream Vera Fonts Copyright +------------------------------ + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is +a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute the +Font Software, including without limitation the rights to use, copy, merge, +publish, distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to the +following conditions: + +The above copyright and trademark notices and this permission notice shall +be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional glyphs or characters may be added to the Fonts, only if the fonts +are renamed to names not containing either the words "Bitstream" or the word +"Vera". + +This License becomes null and void to the extent applicable to Fonts or Font +Software that has been modified and is distributed under the "Bitstream +Vera" names. + +The Font Software may be sold as part of a larger software package but no +copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING +ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE +FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font Software +without prior written authorization from the Gnome Foundation or Bitstream +Inc., respectively. For further information, contact: fonts at gnome dot +org. + +Arev Fonts Copyright +------------------------------ + +Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and +associated documentation files (the "Font Software"), to reproduce +and distribute the modifications to the Bitstream Vera Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to +the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Tavmjong Bah" or the word "Arev". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Tavmjong Bah Arev" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the name of Tavmjong Bah shall not +be used in advertising or otherwise to promote the sale, use or other +dealings in this Font Software without prior written authorization +from Tavmjong Bah. For further information, contact: tavmjong @ free +. fr. + +$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $ diff --git a/credits.txt b/credits.txt index e1905c88b..878cbf915 100644 --- a/credits.txt +++ b/credits.txt @@ -118,5 +118,5 @@ for the open-source EB Garamond fontface. Thanks to Dongle, for his Daedric fontface, see Daedric Font License.txt for his license terms. -Thanks to Bitstream Inc. -for their Bitstream Vera fontface, see Bitstream Vera License.txt for their license terms. +Thanks to DejaVu team, +for their DejaVuLGCSansMono fontface, see Dejavu_lgc_font_license.txt for their license terms. diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 871be93d1..e7e5b695e 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,7 +80,7 @@ set(MYGUI_FILES openmw_travel_window.layout openmw_persuasion_dialog.layout smallbars.png - VeraMono.ttf + DejaVuLGCSansMono.ttf markers.png ) diff --git a/files/mygui/DejaVuLGCSansMono.ttf b/files/mygui/DejaVuLGCSansMono.ttf new file mode 100644 index 0000000000000000000000000000000000000000..80c45b73e9d1d8990a842ca3688579a403556bce GIT binary patch literal 285304 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%0AN*c~gCA(Zc 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 z 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

uYxJ5{X7bTeTCsDbrNs8` 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 XH2;!U?0EYBKmT3y|9Drv@uGhLW8jS} literal 0 HcmV?d00001 diff --git a/files/mygui/VeraMono.ttf b/files/mygui/VeraMono.ttf deleted file mode 100644 index 139f0b4311ad2e0369a347b3be6c46e6c2b730d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49224 zcmdqJdq7oH_Bg)x+2@@5e)71yxquf?c_Sig-y`84XoT{ zYwfkyK7lJhfpq z{r4HT|93*_U#lpsTJ>sT!a{(5oDi?c6=fx*?``~J1hh9p`_UC}L7&F1!F_;FhE-J6 zuhPEx02MvZiBa9)I@S>%O_S@`pz$E92_ux(K>zic zCtSyr#A$t8#~jgW>s`le$aQ|mu|RyZ_qf`KWVCj&>sUn=>ddZVH3{(B;X2llxParX zV}mtZ+cL3c#p>G1B^CAd$i>6$32||W_C>4h8I|>Q^|fUsRZ;ew>cuhk^ySO#h1jaj zURYLFR(oezY0N+y`^>W168rR$>N@+hn(CT?>v$Qj;>GB~nyQlO!m{OMC3R)?_?Y;( z|5e8Z?XUH0&<^yW^j%qJFR|CxmXwxNmDDb?*OdR90E5<`Ehww4s;sN4tf{s``--yK zG9YwGZAo=~S!tBLytb?iA6#5fQoE!q%3fb%FR5N_Ur|)@#31Q70?_T)K>uX<&}%es)5kR&}?iGIvjwN+Dq!{Y8F?PK!5hq zn#B!OW!3d1^@vY-sPNRD=&eLV%%umdcUe8ydKmK4ghRPX{k)T%xCO;MM*7S z-LSl*Rwlo+tgdni3@uS7v5C)YJ<7L~zxLbwee2bA5NHI;IA_+;6tdKfqMk`*gpkd-W24uhaZmWRxk zTNz(pQBrTOD5(SPmsJn&Uj_-?4eEHQy`j3)h4LV>vTX^K{mcI#*}9tLIJ#xgp`c3a zAiX63u+BA(;m+b^B}>ZeFlvEavch7+|GjFtMJsm&h6@aI+46FQcayX1+4*@z_UZZA zMYGZiv+Oz3?FEJTGjlStGVP)1)8RZc%04TnXmb9HB0IDwOwTKtZO_lPr{~SKPtD28 zjIw7H7ZheqpKi}DwC7AK$j!-uYdLunb7y4cB6g*S}7o+S&h3T1D)6xs4Mj?jzMU%4%?Q)YC zz!G5Cvu5JM(^n$F3Id}kk%qh&82-reP z;5~2xt^%Zq`FYc`ZkquYpq;x55Xj^#nGPTz9sW<0F_X#919A~gQGOvX#D&VNoatFn z_VmJ>=_rxx!hAp%Kv0srU$&L? zD{Ix_vK27m>fD1|F_N-DRjepDDHxfGF#xTeR1L#dxh5aN@PzRtyE?_n4cG%Yx&VtW z8(}mfU?#yUDMq;T&N8rsb!hp)YSf@nSy>5A6&akb?0?MskT;P>hQ>XMj>`uY`PV`EpYTp6>- z9e~AvDI^m~4Os#4VlAm8OCT<-Cw3A^7L(!dn*h;f97%+uMbN@dGN4U8se?}~DI+Bi zp+>>g98wMKW8f&AEQdckM5}ICb@EvmJW~eG+zH>M(DIjX>}00gq6FGc2gud%gq=(S z+^XU8%l7Wp?zZlh(a?7d;Drzh0pfD_l*ql?Nj&r%5A^(hN3nru|JO8Q+h5W#l_Q4(b?i7t_Q zs)im>G6<_&zFRiX<6?NC1gSZjjFO)B86hd4qx2pn}D81DK5U{nvo8|Dk7ED9Ijx5i08}K3gio zL)vSgeI>wC=(EEeywU)CMJR}CJ={ku5SvO_Ul5x}xQ?8%59t9l6Qxj3R>E`0L+o*o zCwOHAT(5y%8e}{bJ|Q-x09zS1mB6D0fPt{xeYk1(We*4)Ik^}xYmlKRTwMuQ@#z{F zmL2X^0!?^rC`E4ggJT?rGv-FmqA&t0O*Tk*mcks-v2c^@VdhFSiq+i z&QLmvB~V~j!a4S==&&2B|4y}AjtaJlo+%XGs&#`Dt(5su1^xWbJ-A0hIZ#*&{6*=Y zyirz4kEkg~NsUZ*oy>`)&|)#%ceio(gL;hg)_`WX^&TllO+=X}8de7x0QU$jl6ynG zErNDv7YF4qC@nW%vA|;Cb4VeMZ$(;*WITrIo5B&i zg7AM^rbsK&pvb>U{#DM=YPtFJ+Y-k%t7U6a4*e(;#r%R>|Lu9S`Dl?88W02IJ&tL& zWkdXN+~GJ?Y@LEFT3WQVZrKm&voiKj-*CJuylwy}cs58CK8sd%3GiT0%a=eqq^QDm z4WDq^QlwD91ludz{W*{D&VQ$AP~r*&gPMkv+5w;cEe5yt^K*U-QtIY^ojfK`=GX&L zFjUGo8V0R8a@#KRyc+n1_QlO-JG4@+Agzj4Dx*NL%*Yq~pcg5FBZWglIlofYvr?JE zp}*oAL*Yq9#%}JqpFq3rjv+!JE*Ls46 zJ&Z*VLwsVWKUPNSVu+VYKx?pf#n&p@HE3bo5dZ(MT0bAPgH$OoH0rV9AIopiyU8R= z=2kw*BSmmDo#X@WipVU8Fbm~-IdIJmv0WkDnF&#MCS1*gE1}Q=@8JDVd1TIl<03K{ z+Rcz*DKHA59m1XsZ4oxc>v{6oRA`?Eu+Z{lkz%=zEP#ek^PxY4Jq@nr!Y}rT?eK|- zaAgLZCan6uB@hg6o65-ij4MR{BHCromYuz@O~GIUQi<$nX$< z>_1zEnf8A;3+)At25xY0NPE5rxZMpe~4`!w9Nw;h4Swt zxQ`epl2CXx5n2^M-`HXj;8i4JfjuF0*b=cSg8S*f5qutdohn~dc!)efDI+d}P;lOa zeJgk%|7W`3p$;JZx$uX)MLtfKd&q*T)8Lu{SAl8=tdJ7KTj9nGIM0NZ$OohlVcWT)Tdr{V zxH^EMM8NL(pyKxjV;#j04UI*SBW|BL=uzCZdJ=dU#rqCzH+U5}i?bp0UxRZXZ0q*V zznnWGrAqDs+YOC`-O-2=O)7IG^p6Vu7$ITIuEc~G`zcY15^G>ouFSG=HlWN@-Ln{+ z9inf(b^cceIAR=tSSWqD{r?~=oO@v|10x6Q4LPh}gS{!-{BOSY=QBo}sp7n(7T~Ou zkLzWus^Po@ut2DIx02ii=k7U-k{>`C24(d>$-qs^|HOZc6zf2PlsQ(V%wdc#W1ugj z3^7&aYi|B394MFXVJzXs68Si&eHd$xm7g6Nmtx$65xb&ON@f7BVLwZtPt1hX12$tx zEc~sM|6(AXQ2h5`1}w%E6%x`(&dZ;6`T+cv!`f>n+03mY+`wNaISp+%xm_ncPq)&e zaJ--N!S@F8E!DDDX)+vj!L!AD2wZI@d*r8^+2^Ez9Vc&*v*ZIf`kbaPc$U6JLg+`( z&(?uHIMxMcr{Q}I>te+;m{yS|=(7NE4e6vcWE}^;Tp>VygTDw@-yoaeZzp*ID1Sr7 zYy;qbnH(Y8$Tji^_a&JF$4AK-z(*oRr61Zut^=fYZah~G?alzS-DEf2Kzc|WPpB4J zek}BGBLV6Wpnw41_6R+~BghZ=FrWf?x1S!T@mwBx3!Yy?ir74M z2m63-`T(j5w?&lB^QJq(UUZ*!br1NPFM2_<-aumZ4I}QUr5`@mjH7S`vJ~F z0JA+Z#e^K;3WYo&4`?ojYkTDHX60KnlQ-B6;QIrdL?`pvEDh*c!{?Gm$UcA@0h}SE zh9yDoHDryjUHK#J@E0v?XDz@{nHw~b8&CFd<#ZchdmXr0!!k)S^bsgrB^&7xz?-Pn zk~*P>5KrsDZ47YkJ~m|G= zv3IxYgm=BzJ8Rk7V_6TJ^o(VfB=*){wZdBx`>U2+l-OS+cHusYa3O%b>CN7d*y}Cq z{5FShUSj7Yc6Kd$O=7P~>=lWf*=-QIC3ae3rzG~W#7+Xdlb-B^o^}2Cn9wD$KOdhj z{P`IBb0dHJm_s-|pB;Dd#~kda#9nG)oz3aOixTUApN<>s1%P!#V$YYd!=>y`Ms~=` zo|D+KlCz&ZBe8=Ld)ms{CHB+-qwrJ$J78o_?zad}MzZ}D_Qxlpg+H!kPeijnNNk_P z9+z0#USFZDlUJ;OKj6di?B&z8!ha265AlLdo3Blz0=uxi8Zcb>+V@AtdrP1 zYuVZ$cDKaV7};GCTPd+SCDu@{7aB~gp_3Bl`+U8g)t}_+tgOz-*GlXTiLH=WP4#r4 zriE2kMGDo^Syd!kF0o|^Y^lU56IjI!w&WNqmspv^N+q^U5U!6C^esP#AxMrAlmEBpWNS6ku>lDH{{-CybfOk|j1e+EW-Uv81VNRGgnM zYAQ>FpG1izK*I!y#l!7*KNjc5V&N#(hs9{Tg_vV3I?6+c_GHnW9CjOJwg^!kEDF(W z;YW^e2qPsn0$Pr6u;JWTVYtL1B^DvEa1(QQX9$igHq6ArBo=Bi384}Tu}2FbYneTo z1y5x`&~uQ)0wopzybX|;KS;&jm-$J|S7JUAvjGHKHuLt17Q8c<^klXQy_v%6^Cx95Sr7ciy~NP|W)avkwUY zhnPcsh|mVH|(n z>v6C1=Y^jBJETWxS%0TQI9kZs8AMYuR)Jt>=vE$J5uOuyUJb~6h&WvXh;h^sCjYT@ z&t7~MfIwu1AE1nbD#$m4E~qdJCR3bo0X9_=BfbI+^3pVUm~<9Ha8O`?zn_oI+rw%x zn~Vm%R-;yA<0pFB&6i%cA-buTQd9d<@w+>rHvu|ii5`h8(JMs$gn5LqFprR=5cxyH zSR!|@;=9VW%4^c+MK`36D%vWqSMIHlBs#oEx=v#&sQSC2>)>=t=w7L0w{&=yw21y5 zKf7q&Zo0SsRp~HL-6g%n&w-dqgzRlBDRri(BZm>ya39{`8EdwAP{+1mJAxydgFLr+ z?4ZrYkRUTJ4pT=7L?`-t2$6Oph%?A$VyZavC0lB*Euk;9*W7pID$w&vLig3{SIt*n zxqj7RO|hg{tTyc^TvZ~J=9SEZ{dNFGY^D$p$f#l->tbROj&9!4Ax#eBt;73lmHE?_FP}DT+2+p8&W7md_@kRP zcha=HrOT#GTfQ`Z^Gk6tvGr*ikG@F#7SeqSKh3X%8_SmF!HwwXhV)G@b;3|0DK|gi z&%kVA1jO0TI~Q5ZoYiF08}vq-!JvUYHi3E|_g=Yj{p#Cq0{0YsvDi}Lz@n(k#;@UU;79mcWft(t>`+Qkp&}v@ zQCn*>3sbrl4Q6!HZoy>*Nwuo>>pO`YWy(e$_(WUQ7pWU}D zA@0>@(l=y}Tbos~V(jR7b6)c>F)bpH^jOQp4+8zbc)4 z-=vmjeQYmAIOa|pxBf!TALg~b>SHt641{uK*3Naw*2VfFC0lr~D?At#G%4M(LE*Yw zrUYu7X}k0-YY?q462Yp8d&r|kgNiV#2qnZucq*Y6_ymulRTDWcPpd5~oJ$&IO=b-n zH*DD0*80#xt)lgcH14xcrLmt~rKkV?5$)~;xbpyRgd463;i{-kO?-H(4&e6nCJe$& z^tO6=a;mV=)}&D!ohQR=1L&f)S4#cpV=1-w3;N0@SLiEPlf9pt!jA;Kv5-7xl-Zyo z5JjkfLN$9#u;?GtQe%r%t=BS*XknCb#Mi{@G`mvS=K-@~atFVf-wES7!s$sK*U&cMaTU{Zemn_K`)NfzVgQy3dR7iV7$IIE&?OjH z3wNCUS(ewI1K9TV>kcjBDUU!Km(F^P} zz20|b_hK4*L0V7Op=?X(N34q502bHMLE1Q;5>SM0>>s2FUDHxd)BioU;R$H_B@D_> zX*{$wcaVJ?bf73rtnALh=$CzcG+w#@be7-D;FD$j0(>}7Fd9U-AcoBcv@8*P#pAFBZ7Mi}k6AT=Gakua)t`msN1tgS)%R-cxjUBkSB{KXLBA8HB;2_6Qj25`(^ z%*|J>!SAK3an83PlS5;b;u1+P%8x$aC~L?m6}x z|D5og_?+rF^>do%w9n~IkQ4L-cY>YZPY5T(6RH#H6Pgp+6T0l*LdMkAU|cy)Q#J>ZQH(M z+qND5`tG}b{p;E_?rL&DLGqZqTyBr_7wN2YPWlUtqoZjujcb!uN$aJ1rB!qby@#%& zTR?Kx!SiH;B(Aou2tBgBCQ&Am>9%BE;y1VweVsT~rie}c9Fgw%%JtvJOU^rcFENL|O zF&=HMDAES**}jHj)F-JlduQX^*H$cfwd4b;n_W7lr@g)X42_v^S8M*-9T^i}k5BmW z&kIl1r+Z*5qEh#HQd{SFi+p0aB~m~ z4ffOo4+ne!;Y+<>{6RB&K{Zi1G1LIlfo_!tw~8T!%jJe84f@^zq?vl>9_gRoEqQxM z`74X|A3prZ?%mt=Jg{kYSHd=)ra5wXZWzQNuye}-@9x7T~&2!A|sF5 z?H|0b1`=-^P}o208> z^-AB^?QbN+AKKS;*x>+fxGjti83x#ese*l5wZW}s?bAFY^>*;B-Yw=`j?f?yZU|M0 z0n{Vdfrh5<3Yud@n4g;E&>)V=j+>JaM8_0nhha%V61=JG%@wh-kJ5HbJNZgnd-c0t zU%M>zeM`fr=ah$}%j+L{X#J)wTZAJ=9TCz;(&weir0@UpEd<96^Z|Mo-5%V({OA); z9R1TX&mIDfZUbqeEfqmDRHLS}~o zC!ynzZR}wGS8s9Z{v@Gi=8g5jNZ6u9Hh{G9WSbiXQT9Zq!$(hABgEFA=vFIO-H4~+ zeDuRc1bGb$GHHUm{6krgDI_=!gw`ud4I@dnsv~DoK+lITz~PQ_a4fp?e;C9+9z&u^ zu441fhc|B7`LJ|u{R7|r<>I#wtZ&&XNms5&H}_6!TzyyLx;3jCxihWz-M6c?Y3n0J zAxG97zIgHQx+5VWukAf|<&(2*XX&C<_uRAUuEzDK`|E(BY?-2AWSle9LnN)f+#nCjFLVRi<17&-zfjBbXodm&O=;_Ta5i%LDV#a`j#%E+H3!& z8tFc%M%paZ1q05CU*#h}9xCGRG;sUKL4Kbo&_JHRR1ZcZnm-UL%o)QV=#U+4UmqVK zU6fM5-2w#J{{sY^c{-dPYViLU1RT^do&-`A%ncx(fqBgaiig z-AYsdIa63Vz*uEF#40O6??RkbfrkmZz@8PKQBjUW@)4+T2`Kw(y$~2_I4_z+`PF^T zvcjJ};zJ$#dIORn(cE@sOQ^6u8pV#su0)>1j>yD54_+VTJ7F4r#%DX~BzhJYWL5 z1$i^*M-Ws~tZ`=OV8*Kw^rFMp&zJEWCpi54d@}<51dbPdO(fX7&9q(L>d_LsDMYmU zdTRtq{OlS`zYq5|Q9BC`Lw|S)gAs63%758iUA-<{yJ~&|#)o^Fz$?=P`3H<@7)}I! z=CtH#B~AsrU}_!49qbxkG-pEWhN`^7ix!-yIC^>Fg5s?3Gw09K2X-&oS~z=Las2G+ ztjyynV@^JvyJ6nUjH2fF zvi0kiEo*GL-?5?a@weW3ykOI?Ll0b+F4HO0I(m6ZT-utk(xcLRx{9V=yupR6fArDy z_dfcl^hHft=C{X>f15o%ZBG}(GcQRmN_TmBZT9t{f2B=y6Ma*<{&(Ps10;V?_KI5a zh%=oyAk+o5b_l!*KB7Yqc#VT;)$pMXEz=SQEJ`sgcuiF+Jp@iu096s?%#}un)#`vp zN_qqal-p&h<;kB4=77pH(0!x^JA7EhD4p;0(-IS`Ks6H{)^j+X>3NMxRBxhNIrV%p zpRy2&fpG{6<0^V!=JluV=-G?a{ogIWD1`O%?AaS5=|%|_#2BnB68;XLM-B5FJNh$U z(yG<8TDQNHw5|w6P6+hM5eis4iz^a=jFe*d z9N^3b%yvi!z2jepT7G}vU;lh?!}^D$DfH;4KWx~r^GWHt^rMu`o$bH8X8VI%xpHa3 zinVu??tkTlt-ts5zR-3a=K|ZnBFDps^CdA(Ki}ucVeeLEcwT?l+^T6|yZk&7^dw%4 z^F!1I9W6vnaS$82^}{t&R$|}L$$b2@eRHLcrPDNx2F~3#ZA$yhGu_>1il53!8a|x1 z&=s_r?ixP)!gwcyyl+TvN`GMqA9`Az>B|MOQ;C^vKO~XK#{)rF16El#Wa7(#8Eh(aCh`Pd}{`Vx@sP0-;2`ERt@Ram6aa7_fmDQJ-OV z_7`zG`fIrpeJe4t$!_oeM2@IoF2)xFWDObS^l(Au{{$vg20KctfK?m^n0q;#!jLNL zOIFiAk1Okc6cUc@(&YC3WWci=WK;k$3M8q{5MMvy&HP#eZjn=vzi*J9jP^(nlOSjV z>(GajL?tScE-8t${~|F$={SxT+5f_9Ct-k%Fc}Xy%f?Hu(v-f_G(~z9c=^-1_I4g(5K5|Ue!`9eR11l6 z+VmeGsGI-=@OhTm-e;9Q`wF(;D_l7%rc`QyV~iZpikQz8 z=^%^DCl#ZGDGfPJL_;N;CpC}eDOV+U3pRDQ5Uw80WpgvQS?XdnmvffVm8eYXVE3JLPTfd5dwDK0$*XtlAs?gCRmevWTf1h97oNZl97NM zg~yO%wsrIFU7I)W+P(R$@B90&f8Pg5r7vj?^^-mWf88m4Mty0HbeGf!nTRcPGi{U_ zp?9>O4Zs;S@gO6eKD5;gsfaCBvsMj@Ekc4}jD-Yg5H8>T;ylo;@5;Km>m zz=y%yl{SCX^w^&5QZ7AmgL2Z%pT0UL#P(l!XyeA6`#<^M@<00Fr4>N0^sP*KG%*b67~MLqH&e;&fpkTcfh6hVp}J zR{5!Ke2;wCy6v@Avzt5q9BqV{MP`7sT6$mFHMy&leSa&b0MBON%thdg2jo$h0 z!nC4;@l0^=Jj)Py;>CEt8YbRbbi82k)`(2YEF{3lw7vqCX3vjL*SqBuj z^4zJ&LL|W*)u4%xliU!t!V-wQGJ+hn$jlW7n9co=S6z7iy~ESiEPnYsZM#mz$NT?s z`GFm+_j50M*6f!m=<3Jk_iq(?{`S|0j&Za5uim?9{Z`a}(6K3?V-e(c&hZ94XVf`@ zf`il=PNj7O2M1+nbwR;A^?Kg(NuO2=eV#nYw>nxZyCQ?Mx?q153HMJi#(Sz#LgONV z9LT_2f#6hj;4c3J!NkDO9-6F&A*1GS$Y|j$BrwdFilZ2VdBs4;idp$!8bsY$n;@!0 zMzJ)8CXE^f(JZ?*@1+IJ`>P&a`qz`v4}F!Fmesvcv8%n|f#rWWP7NQ;>=O39F)nrE z9g8c%eB%H5LeJl$queeu>!90 z$%(cB#{&$HbuKAw*;GltnnOp z$KZiM3T_N|0j9$PhQ24R_5fKp4N1atOqpS_B|LoRdA-TLdgiQEAtwE~ltpnInK@?0zJYYmWDYc7c0c!WKwoZVAKYa7Z^+{0W~D~Fe-);tO|PjMQQ4H($tIX z!bmWpP;5n^eoGk(dh)R|6Fi_stKqd8rqw|%k<;m5T&Q4@2T2pPTE#gSrzd*qAo>g~ zI7u}u%^uOI^*9k!)}?hS66;#{>`NW+35uI^BLu&4a!iGuLXEc9M}vyAAeaU7!CFj0 zkJP3?%6W`-4mU^8*>vID2uRzE5F*thH4a_4J_*VclK8R0IQ3Y~DBWm%5hp8F}8Bz%Ions6F zuk#TiXe1jhgzJiRtGLy|N}UdD8fQ|Q)SjH5Is|5ABh?OF62u>~)y29pu8uRKV}(cp zg9(f$X1)g@ciwwaI{oN9=|QRCeR>UC>l<8Re@5Sz+y*Ffv!QOdXMJii+Zpq7TGd32 zw5l`E)k09i1RiSX_*5Z?q^dOX_;by3k=EZ-PLD(i>IwGH@eW;1m%S&2U~p5#?d&_- zzli%iU;$N<`~x5f4asr_sBu&<)X5Ar=I~kth)yUUOGNbW5LkmhQ3ChDv4DxZ!)i6? z7)~R>b9>?9OcD(_%+B^*1G($C@B4#=p4~sywD0C00LtkFSY2BQE9fc`yK}Y&>R_`sAcbpPW_-fz&Q6=hF-Hz&GDW#iD2PkA2O6^)0J7xJ*ccIP$Yq9FPQc zFl$%e*SL%$?!=zwK+l}JXVyVq6tHJ9UW6q$SX`2)c}mX^>OzQ~#5k$=n{PzVAO6-X z^4Rlac7O*z0anDv2{|n28>kjkP?3OM_S)-UCMfnCM!A>iYlo!=qz4bv*MRA7(QQ%# z7cE-_3G!zWt}K~efZ|x5aIu*F!sq}v2L&8(v!DR+weeTE>tZ>yjCX42QSuT`Q{}ZP z?5j79Og*G2ntI4sG`INAgui(b@Ph?Y;v8d19y1$NkzS_0yQO1dxwM6@0zJk&a~Qt{ zXMLpFIRd zECdsMxPX9JRtq>|P{lZBU|evVJuW0Jw2idUHm*(ErrYP;W^40l^KJ7p&UZO3wCPF7 zz*%?lWgJbCoti3X0{Ag+$iH)4;~)RSUCSSNmcI1TxaS+6e*LHad`~y+TyS!3`LW_{ zXU2!yxx_nGl&yH{=+-5m8u}0Fvg&%RnjU3s4$B;+%dy zP_5Nu(lmMPGIjYs>PxKFNj`c}^veze$`T+%L$#JeB%JRI%@e^&xw5E*-Uro@wQSkA z>Aw3mZQRoTNz|j|=f3#zeCe*3&Q31&?e{~X3`lobe*7WUw1jywy z;Nt+!`;u6vpMIMGUKF;?_oR0dGdF3vFxg;*R9Chita7_^4Q5Q!efMk01`Gg@kGx~b zV}(+m^Z|8H{Lw#!P~f-n1w3(BlALUoqet(dMH*~QXJ^c= z((_+_b*^l;WZJTE%v&LH_IRRF)3%72JrC=O@)UKc^ny+2O zx(FOYF8+AA(=;GJm0ZuD;*0w}Iq_`q$*RiJbETi8_o@Axx4-Y?AK0?-pqX1RM||)l;YRw=?^mIwf&%~xU73X#IN4KTym7p$0L){&36xOf^}FRkm8dg#cfo)fsSy#rMAT0b zt=5pqFj!#~M3$ZT%9UqZ#*|dw6>%~HfQtt%{!X6tlQjq z_4C~Q(-*Z(e0WRLBURmBebv3ZCAO1Gx$w?A7cRW_zI3@y>I?Aih>6;FNWFH!JUW)D zsG5$QIS1{%%sYRXcMu0^p#F)0Y%N{-M`0!`k|_r8OH1!qzpb+~{y^Q+PjManQ@D=S9WOrJzghI`e`4X{kCAJKK~|a2p9WSL zW1PO~4x;bYK1xoBTnEo`byO5`$yBWhDmhYNg(X!U`w6ba2S}fQ4Tf)6h6sbX=R35j zubNg#AJgE@PJUruY;!Zq;3h(niz7#+nam9R7$BcA#u+HU4umE(?O^6^!n6+`;)yXXHXeKiM$lqdVN`KPAS zZ|zwt{tTIr@YvAq_ zz__Z_zF<9k1Ygll<)e;d5kjPD92*DggDI+H^%Rz)nk~*&En}5@rC6z2%~lDk#nq|+ zoa+zC!}NC1PyQ}VqL4vdw6#n0>{~-GN^|T)$$^V9db5~IkuQn`u@1PN(=WHYyJ?(BEI{NoGKd-NmPa`!!ZE}ddO-VboA z0B#M8vrzK7Gs4Ge((o!0=r5|g^i6iw<$uc8tRfbZdYYJLnP$oh@R{b96=uHHmnvsz zEVPY8!RU-p#gVpJv}?zh?jDfabvFpfFgqn0iPLUfxnPcj_T;+0};;CmPv@=qrm~?CEw(p2(6s5x#mDpcEPv(JvB~5yaR5VsoCbN1?@R1#s;ty~YamZ@# z&~g;6qUrwoo3`J7|MoAxzy8&i*RQjW-haF2gAaP%et(bjSLq+1d2i8Z*uE4*V{nXj zNi+E(=okHEqBCH?Uv?RH(bMcyAo$8jvez6ENr2TI2qmy6D^aEr3u8bLZ;35dzVs5h z%+J3#SH6pWvssBNHgE4gD{7mk&yrq|zJf5~>@517E3`n2wn~M3Fsy!JWCIutL^fTf zUH+$iPX)?x%_N9$CJg%Up%@MI*fM z%}XzFBM}4e+5PuTpA8i{7V1sM&YIr*<8_Eqmx3m203KOLK4kn=I;hxUt;R0RDHS9% zi5hGl)TyCAg!IkpI6~r_4l}&F)oig7JGEQjZBI1O9A|M7C!J_^S_()3Eie~Ytn(qG zfqqlwp%NbQ8^+z0bFc&Wc49;3ouk?6m=W*3-v1WA@Pn1>LWiM!>;X*?0hH+vrK&bDP&mpC$|6-tsDaX&Sk7H}z~0Djo4$6TZ?_mVSJAI6T+Qd4Dg`QG(Xw^Cmq#;GK)p%<}(t9lxL?H(O=;t8Kk~nA`EwF`b zpR`~>!-bD8v|~sj{9ZcM+~0QhqMiHCa|@g41RV9iU4MST&qn<&Ej^`2KRyKj(iG|E0{s&VL!hLEP?FTuKZTc=5T~O;WuJ( zP0iFiFK`Zyb5G-GSm_CxMYB&xwO@nBFJcFOY6D#0AAb>W(Nl{vO9$>%tI=XMU#A7M zG?1eZ!S|{JKoXNVfFCAvY(tVcr+zD$142QUfvR+CY67dAl!T6w)Pb3{lJ9TQX?R^Q z38sOZ9}D1N4~)iN>!%CWhZ9JqbK$~pakwf>9i>mY`0rUk;N+zCy4T%C)(X!US%DkgA=movmHU zRSFf_HQYM3nqSA?CETrDr}Y88xpO}hb3YxY+aB9@xa(*kcbHsCC* zn(&lYgTy)45tpMDF`mKvgc8qO`QN90RPy>s5JW|)a$2dnlde{Yka1N(&AN6hKT11? zpQ%*?g&GcXJ93hTUm(@c&K_7Ac&UeWN;R+3;WUC@*#AX;Cw*B;<0f-H(lYumQd$At zV?9u6C2h_ugUx6_wb5}JJw|308|W;7Zy%pL|})HJD1Ta2eX zVEcmsv%prhHOH9c0lKYFX}*F9)0A6M;e&ZeEU*G*fbw8^W{efXH$UEdrbLphh zw4&jJ^uyS^yxj}B`Mkb|*m9)wJjm3{FM^o6*crfZB&cmbYz741ryxRuJQ7cHh?u2C zi|R@vV2Ve!pQ!b69%&5bk(^$m*%);eo1&h@iq&Oosk(vPrPdBfEq%hG``2S{-(23= zJZr}fkL~dF-?8V1=9y3jZF_5VVXyeVYU;4O;0W;b^D<$5lb=_Zl_!3|UgOO~$IFz% zUKDv+{adul3~|vPXG3$2wL;+1+#K)*x)q-yb0942a_07#b84#R&fK0k;l~5ZwmY5M zmmT58I2IcV7OcrM9`g^FVtk|VRult(@J%`i5U4d zUl>EW0Ah>?fJ`KWd6)W9FJVO}paipPjAJ5jbpTkek}FnW0l|h@5`Oj6=KMK#c= z3dzv>L!Dx)fxYIXx!-Ws9uOGdV-E>7Sj8YC1Z@7Kz{eyOSbe4j#9F6@gqlBuJT{~b z;J-4Xkf-iID)`jY&pvw_(j9Qc6@4fx5$=K>7)#23W#~5sV`|%Tqv1Z|eL)+8`DT5y zzR}QVYzz{>stpZBRZ!rA3rHA{qw*@XK8(yxbIvMGOPl=&7X3UlHodL3_HpMpdQhqT z5$B}Mo|T?fT-?{MW(6Uub7~)dyf){~VK=tQ)j+^aNPEgvHW4IT;U?_z2fq$?&VbFx zQ!N8NN4ogT6Dw`NXW&k@Y60Adcijq5?ps=*}yaMYLk3t%+Kz~Sx?BK zMvzS94%v>s@XRmoO#IC|Py;aJ8S@ZmJ8rp?Jmk*1L+_}>A$LA>-8l{1!MtDu$;K;? z6Tb}afI!?ZQ&%iwJ=t|4r1+ww!?Kt$(A5@-X7=&4giB+-f?s1 zmv`LUQSM+rZfI`qoCcZti^!eZT>ZGYBhT$*N(+C6!7uN)G5F;jHwMZb#J~;Bje&9p zF>v2;V<1PhG6uyz!{C>9+!*}wjvE8z4r1VjCSw4WZQsptum=R!yUe~-~dY!cR`%D*$tkd=Wt_53piVOwBxVWlJOklX%hRl??iu8u4=vdej zccgP;eoa+=!5u4vZ{lO3YcqcL;*rgpj;^mMC|F*dm%jpMqCL{9yaV!Io%mhydD%=%U%F=%wEAd`oeB>;m1Oz+}0Bzcz!gansT-5FkG z$DEww#T+80$`ciH%4bekH*wQCS|@GieESl6Uw!q1kJ7ga9i358&!2p+S&D6Mrx%;A zN;d+5tFPW1&+7rB1Tq2YCsMPAa8-_G zz=yha{Gs0*D6o{*+}-;^BEY}8{JrcYAbSAb-Udtbqr%yN>CGu6%ii!aUb=Vg{PAO7 zeX)MY-i`jH`B)&uxy6T9I|{-oXBz=sB^Fm%#5W;E18L@*;Zx-V39H*hupi zrWa@8z=1Tb`O+0wyKy-%%(bK)TzmI3&#t}uY3|0|Paj-!_cKppe6bWpA=cIzpl-+l zI=MyUj6^j{V6$jE?C<*!ww=f&+uaG*x*^!Yls*0-@x!=mdUE@T?eFx$j=P>8%f;Xy zKW2HB%bi_cAmrm4ty~Yq|4~fvw zVG*JjC=N4wM~mi6k{yS`^L5zcc}ZSa13}6D{tE1im3lDpggK&zOdVuV(!9gXrO}c$b#F&lwjZcRytKG2eCsYhB9{|7(? zcP`Ym<-qoAX4cP#+6LWxtyYtv*NWa6t@k@7&v%GL`*!-J;iM<&((tzeFHW<0n)H~L z(D*Sg^E|8HJT03$Nfl--9;XVM9UJ?Z^eJRlu#7tai~xk$IGsbTTro>uLooC`*vtxgjN-C|d0~JGs_C|O10^J=#G}#h!4+iWK&c7ru?`RCig(^$T;MS_ zyta8+{P^hPd%q|zpEG4j=DPRi%$YZL?%en9S^GZx%$qak{d<v*X;X7ws9gF& zZtm3FsZ(Fza~G9Onr{>)jyw8n!3gPHuA}IS(P?j5rvVN~t-BNzVi{P^1LU*W~FU*Q=ayF9@E;l|(X@b#;(dB1k>nRDKc z{~8mP{2IH!J`%Q*FNe{qf|nUpI7gd6?~I^!7PUrg)@alj7NdqylU2_I`i>R`x0l(3 zFAuO77V0buJ;?3cLjHC!womHq0j9_a19)2jxFYaJ18EpJ?=rN`64vj~2Ee-nV7Vep zenA3MQFiRB-Nzl-y7pl0p5*;d@xDL`pjQ^$1Vhl@MgM_`WGRTt0E_hjf0Z4D_(ERC z=YDM+-v}9g&9AQGV|@{K?G@?RZd}GkZ=WV)vj^bqQMfB-9@b|4jVG7YLJ3bx7p~VW5NnE&}dw)4hHGQ&|UmXd3M7*mCZiXg+uD z9NM{J;(#4Em%$38I_>as23Tt%ZKB?&ZL^AIwWk$c*Z^;r;M5wyMC1%4BxKM$!^$YQ zPu#vCdwGu#51R_=J5=B=Swu3hH#wx3+kAcP6X&JFot)Ue`iHeooTXDb`{AubbX<8) zd+$N%OvPIVdr=R-9KqYYV9$aFS>jAKIN;4K@Ub|ICZpM5G8thX8q>8}%oIvlRIQdn z>`w*_W>fTnQ45Jvky~ul8e`FazugV9UL|#O_3G7YIPZcbgdwR3Wl9A_hLAJGa7_NN zFlu8V7Je)2EKQW&fcIm3EVY$&(%q}hQP|4nDv77-r1fyp*T=wkLb>nFqx>P!26+;w z8zsw}V@D1ThYByk8v}#wo<=qzJczaW8C%0!{B}WwVU#`0GQtzmU(iAf46_UuM~Vry z(Uyd;q$s&^?xZ{e2IO5y31#6KQxzx8xIY!`rF;|jd14_0m^ez&)pL;jrLcKjUX_SY zMI?uFNw|U6+m>vjbwL}7c5l{d`!CZUeCuXDwn5;I4IlY^|LP;-o0lB6JHGF$dnRRD zDUHpWgXOW+TcZ2Va~E!#A$=%qDk$SVyG@e*fHkwX-F7~^FNcc1$GXwNg0oYQ2gAt? z{s2?XvPWs{ebTzU5)Mvm)9nLB>c+@kD^%JXC9!O`^0iA(Q^-8pyV!9UzH zy)iHScQe-Rf9!V)ws3V@N;fTE*4R+LY4OITRqOA(*|6?|wkI!@Zn%5d+kbrK%{q*I zA+neE%R>zhtTFp&KGCV#_)iQ1>{J)2pPCQQ6F;NY3@Wc+i~%DY1M+dnpgmMpA-NR5 zBJT#{N(Xk(L$Ur&>BV;G2+eJWoEZmiW+nVeJ`J+qS`rDnHRL^J^i%$ds!c7bcoM1M zB6Kou5`am#ArB%2d83(^02-Ubuf#2DeIGH{wnjTTXzl?zwexdH+Yb9R+>{JJhZH;1 zK8l|*fUcoxK2pUI89ER$2;IZsz^!Z;>=v`IzRT`iakS&B&pV|T4oF94;@&tpUjk#) zhpcmELXDe7uIJO>4}+YWC)T)mW^gLOtpD7qwF#elsTkQ}^r050xDyzx>!#|&GJ___ z+fqhSJxspHPlchqpw@DX02E&V*$lt z%%l%UHRq)}X!9KD{C|{6x&8|^tzk9&*EoGmSZfW?bXqFne-Albc%!Xzgokf1^A?## z&!|;wGHna+-bGHsVn~RuPGb+|h}FF&5+cvN+{rai!KexTFZQK~G;USxM zettn-Zb3ipwC=k3Ipo!&p=x|M8S6BXh!Bmx7~v(FLi|l$oz&pej?fQdunB9J&j=`E z`w-U8<%;nuaACu)r~!AH%ExFkR5%Rb4I5};*c6i~XL9oW!-mD( zUv}he>7$-U&R^bFcCT($e%1Dw1y$R*s#$-Sx_(1_RPcmFueoPe5;)x~8XnIcj$5pgdMBK+&$qaPHhK zyBTHi6>OjUo`@t$lW@e*T<+g}g`A`R1Gc+AjMGXzTj#M>R&aY$-(~FW5$G)idV_Z@ zy#xSFP93EE)O;f+HlkMrD+E&OPJk*s58Sx}pGVl^kM=(-<*N4mus{{`!#@y8!OizT zJ96Po5oyj4ou^UDTR7EMMsF+k75T#0>q&gPw6wyqgn2CSD#tZzoT34LQH!w>O)d&? zIY)>&hAIM-FklQ)z{hWoPc}uV!lpRxm?sq-Y36eu>UT~~6X-^Re#0T|VBciciMXtn zw)44AeBvPSFTp~q^)PIt{4=$J=kbFVJ*r?GOB1eLZ@V{eJs%DPV)YI9ln<|%{|3{j z1dq|lRurwvlA?uWuttDu*h))l!JGXnOjXw7>vM5tIWNX%BlD=De`A5wx__ zIa(tU-(a21D3Zwkgp;pr;r|xD)?4iV3cecfwdI?zmJ#8>p2VhMkr6%y%~IX6V7An= zas*&6S1HPGWKkjoJV90g3-fl_x88EaX&gZJM( zYjWj==H~bfh3i|69qd@ykhpeY=H|4{gZ<06J^iJ8L1vzFT610Cc*(gUJ!4D#`X+wP zys(gU0Rad5_41y`Ye3;;pb+07;*ab0e*f_SnylZDuk|efz9x;27t<^?En`c)Dj~xS z!T=;)6o5g;H`ojy3@+R)7LWu(6f4T>>dMO+>Xx*hKlgO|x${qRPxQ|d*8HFLzC6CE zD)0N8o13KB)1+zICQaI=`<5=WrL18Ste_PgifmFgMOkF0EFvO^wg?D{fFc7}&|y&7 zL_}}_*<~v7xS)bFE{~4lybg32Y18NXJ2$r$#OL$Q`~J&qPi}ITbIv{I-1FPN=h@oY zHP0=seRkUUeQ%sQ_r|{SO~X+e&OnCcN3}bFzSSiZh`Sv1FQ3Dz;s3S+3dLiMp5*dP z^4KQ3CYpfO>zSw>mxOVO(fO4fe@dl-oi4bG5D8gaQcP?E0~$g!P;fB6mIxpmF&Q}A zu8K>uC&0(=GH|#X&>AOCc;1Z$iDEog8S`_p3FmZpaZ;28Y6Y3E)9k5QHgT z%*mLNp^W;W2+oAyQZN2GU=(YA$WTyHP+Cw{&|V(OOGv~PFDSI;G-eXHHra}>48euC zgoA5F8#mX;xKjKW#AmeRFMM(4U3Uzr;6L`Os_M)C9(Hj)`hnZ#7nMEId%{ym84IhQ z-FW1{w2{NwKhmY&Bb^4%NlSj@u5HWt-admS-BrDiFKxGK;o|3Vmf8X-e_U2vyfrJQ z|E-mkTQ~h_$H18nus?luZcZ+EPkWLtATH5ox$TL1zupn(X?M80YC>3G$t5X-J>jDU~_iLFZktYNw z%03ZtW{NL>xw8p~W_C!EcsayC5i<{wq3}uJmil|4_5y!PQ9@iLlPlr(C8Z^ZQZJU$ zt`lwFBV9Up?3mp1y5aVrJG*ijP;^#A+(R-`u>UmZcORrhwump55!fw3AZY{rcaiLh zCBR;Yb{0FM0sTkVfAUA+@RclSDIXnP+dPS8j)8m%Y;(hyz;lwvik#F2nyB@*;RllNLgl=mLm}h}|@43Bw02l8R9N z;la1w5{ywsno~Gq1~j9xc;GBQy)qcq&1;lCpF5&CO?zO$zxQd%Q38Xl{T1lm0&H>U z)+l$PFA+}&w-By(`+SKI{HzwO!|Vo}g2_!#3h`#AQSajk#@$iQrH)@>ciW&?{YBoL zyw>K8O7$gr65`D!M6Vf{Ly5Wp@dtIGp-sR!~?LRho z6X!e}KDxAdVYu-dSL`N#^3$uNmzVO2SC2X{t_Si$^vb)SEM@GLPCe z(|FT*2a8{Cm9vx9mt?HZ_qH!A@Um=cdm)Ysu?n0sY^k4hBDftvbt1zULIlyp>l;>` z*E#1dhBEDUjIOsBW69`R5i!T!F|zR1B^9?l*?;)M+=MedAJ@G5vM|S{#B~g9>r@t- zB%4Y*h5zzO$M(gr)Vn)%+t#J5j7+o`&@I1!f_Y(2a#(g?21P z1KdmzHO#upT>Ec+g&}|n-a!y9C{ja=FU0J^5lzVW5d$h*5EOq2gmW3BWSyjI04UAU z@G|L3?b2T+$?skfUcWPdKH`uAC>QvTA-6#?$xV8;)hd~_24>VxH*45*EuqAbeOmAu z#D##S5I>6Pod7_Tozz#Th;lS*mAxD|5WX0`cz|!{&o{Jw74sI#9P(?KX01^p%G5@2 zvz|`}pE_OfXKwAmHf4$u5h6eZbLmljCY%Gs)ah^s^_v_B59=Qub^spl<^#WeMcX0> zMV`kAS4|Jj1={i`nQbs4S|(8&m1y9Jq<6=QPp^KEbZCe}Cnv&4s)W*`xTz^TMnPXA z1U5>rEGl+%vizo!9tXUr4wDO6ew8z1`Bl$oBWD!LFP$lh+#}9l^!Gt6-^Q$NM|4HU zkl(t>9Bo_`wb;#8nP27Z=qM@1X7a@uEG#d^r%ezDBABn~1y)>z2`>zccR`vfnb49P z$#`9(DS_pRw!@tvT7J8EWB8Lx7kQ@CAFz6T;QJGPwYK)v&M@5c>*jk39dI z@TPG6*YbR{nHBuYUctY_vi59jsJtjB_*!>*lBvC$CDr@zowtNM@+xmDdmdr*hFJUkeR;(=|O!~YEbb2ESR&W+1Tinr!u z_2}NS8%GEVg`#xn)}fbB3{~(w3|FwY)aY`AuKHf^v8_`%`P*@n*bOx7%@msV2~;xL!>?`0LBe~ zVzuH^^K8?>H6y|$;lry(Xbzv^4~8E;B|b5-DCed~&KdAH*KE|WU2q(VfEXs~$?k-| z6ZQ|^r$-QZ3;ZIeO$o(_H62=wyr~3T%=-jw_`djrPWTk^&J%e9iI8p7>_VofF^~}> z6$Q&LDkvSN+apy&yIg&zW+S6J@h<)rQ&B3U;v)qU2RM*D4XxG0$oq^ZlEO?5>!LuH z0d37^;Pu86i4Yb%&W8u_ZsWZm>PvwMT67P;a0y%ZK2rGb+Dn>G8aD_n(zI|u9-<>3 z89hr0MZ-B0AZ}3#C=HMwAV7=ARhoSvf)yC_(!Jq%d_IN0@QYz{*rJ`^bgJpFrd&?D za`wt;IS+Gz@ScO7JA(~T-gu^3@|9VFJajrm<^otu;GuI(WZ?f5zN3T{6W*2k%H1(~ zf^2>$At~15wr1v8;(Q)Mwi#ADmrd3fTKsMg!F^|FTCyy81^%qmB#YZ&P0mQw*<6ln zUmR?GY-X(0QKOrgnUo5>B_g>H%Sc}Dif&f03&b*rrfofm19VVLR|TJG%G?5;3?Qxg zh#rU(wIqO-Wt1szt!C7m!Gq?`9W;1OT>YSWU!u>yWmtXw;G%-z1)GM{`xE`j@8bMn z(t<&=XAc@O_d!0jerSE+(1N1DdG*6K6V~#^LG{H$^NWV&)!)4ZziE^WVoMM#Omr>* zm=|&r+p347?R1KD6q-QHNv#A;6Z{PYLk^peLyek)Rzo>xiC7^A6%z|ND0GQ$x*jzm z+84m=UWWGser)7r5Mzjy9M;`NZJjI~WNYQM#&_&yUA#fIz#Uk&LEpwJoV{Gpy%0-> z@E&1r5avWuv2^<82SOQExHpuIL5-L`$RU{QNuxt19$~ZB%-geP#?F!bq!oL@X?u3nugX8EegU=YUg6zLjk+qp|OIW)F3b{>K!weT^Q#&2LAzsIoWze zTYANcN|6nOCT*okR3kx*3OH3l)JD`NQWv=l0b+<0OADV>Y7+DBAGEVkl_hQJp?a2( zMaJ*Y9cT8a<5nY#trlORl z7%0W{Bv}qdd``&kM0lX^3FpE?_@*_Ie>L9(Ka}P#(c9liLFsGFaP*Vwb?D~!E=<@e z4l9NXd9nz6I4qn1WVp7-unF5SiS6Nh_wUVP*I>h9UWOY7P~pUkpS@E|%eWuj{{L@N za|B=RR0MlgPjd>a+|S@yY~ZOgSTXC0HPxnK6$L5H4}Pe#<%rXNq;LD5m zZ=v)u{gIpFH8)8e+VM>0wRfnzX;!<+kg+m$mRxC1smz~c_g027g9m>&s0tAR=Ud^p z#aOsdbOBlwF(61$g%MKV1lV=kkPUqs|Aw}3g>8@j-t~Rb+5IM)N9Puy>1#lqNj3b^JW~9%7BYLyt$%x^~hd5 zMppN#c>x!0sn?wDRb4F(%%sb}uh1Eho;a|Q@&0DP zro9C=Z5=FlW<*fHstqV>laA;EkvQxFq4zU-~$WoIBmACUYj8f$m$tR?gI zrAx@!uT9i!ho_*2y%9=g4!zYRbBEq$k{u`F_3{aq$!ml9U+=1n)mKKrDGMB!Y9Rbj z$gp^ETL0B5n1ylOE2`jy^NJEA4+FW4BIocM4TR$nvv{bhftihFli6&tne4V`o5SX` z#n@c7Sex76iD&WLWAvCjW{<^V_1HXiPqfG3ar$HYE`Mx-JKp1mZ*7JW*B%h6J_;x! z6;H8H2uh>MUCGw;RA~+$GdLrZhF_M9R6bYy(he$%aaP>EXr(t<{epqdJ8MU1R%jbB zCq)zA3~m^p)hCFTpw0qk)>#_R{F1hDC9Vx>vosrYeITK>e;ue98g!7Jy>3Nw@k&Nf zlAn>T{~{z*rFqZ-R?#w6xDYBW!;9Nim^h=}Ggq?Nj!In|>VJ{yPrIwTH%>f69PEvehajg4JRE+bNE}y- z6zd2mW(;AviYRh5v!9%gi|w<;KZIYBvS zvhYSaS;h{7&S=>S`4#B?Apr!oi$A@mZ`PEO&IA4V z`8L}^qp@me0dzH2&mul|!FzvnoOir6JcCf)mRDl2x#nliP7GfF^r6)8z6t9vHbit2#VEUATS<-qt^;6x z5UOn5ZKqIWlR4Jr)aYX5Xr{AS46)$6PBe8oQ3O>4k$akbMdUJB@FA_^)u7mAfYOLC zaa5!=hWSh-pDhBJJ649LMWUH`YQsbxB?Xr??>{>s{39rpK(G?@wKPIOqEJcFw48x< zLMMEl;a`AF&(6~hX9OmUxCg2>Y78{t2N8|KdCK?O9EM};rLt2zRbDII!Bn*B?If}R=9c?v8p>ZW**1CSP0%G%Iv z4!6_6nZ;_e%h43B2A9k@x62*lii>l1Pl%6m#W;1bK)PbFzB+Sioo=-`c5Sx96{pFF zamH$r4M6s_vE&Sgrf0IlAV5|`-wSaOQll_t|8RnsMGOt$$aAg25}Ia;@KXJFRCNxV zr?nYn8O822H`a<#3@vykG3iJr5ADA4^;cJ}oKFeZlKZ5Gzw`aL`|LcPoV+d2Kkv!a zD;GbuvV%7GVfc|F&_#aCGochTKv-IY6JMCFm?!$yR$$jJwX0WExR!f}k2U->ju z7FRhQMSiEq0#$w&aTjPu;-8k_t&GB3(ry=DQQe2GAJzTCHBsFP#`=E})vZ6; zy#2ai-LR`jd2)^Pk)ZC^u698Xsfv@(N6@u!EV8&w?kL|03Yj1B8VULr<`jhdYBd5Z zOb=j9ZqP|Wl@rmrV1}WojKk&%aRTTZz@i-%-Y}I9<9AODZ{S0w!e46>l*B{$uxa>B zAK^_i=o*yB2TIR^_c#aZO?fvH-f+f2>0q~qR~pZ34wzj)A&dRzOP@u%D_=Fz_iZ!8FtK;c-7^AFF^SH~ZfrAjd^Tl8hET||O zLq~aUB0$#^YDgSYNtx=?5(yc@Fw*nC@iondz8!u0sQ!hMx^}DS_{7$V85-;434g7g zRouC6YU*6Ccj5izGp13EZ<3a1o<)r_*^q94`C(2}&BcuPG;kBXS@2DVFkJ)OFHGPN zjLeHFI|EN+i3Y5E5EDNy-9Ar)B^t6&Z|J1K$ig3AsX4v&SO}_hiH0`jBQiH*RueBY zUhZFOFP$AWa{sFxCU@*LDR1=j3FEt03>`7ND))hoy`~i{-!f1h?iyD)XOSzW#*=V+ z&x*d|x^`;cHO^fV?U+8Y_fWjc9$-uk(or}Z=S z>X66JEs597Lty#}`jQ>V-Gs&@nk4XUz_(_QhXR$$01_l&Wc~k0Qy><50vHP`aO_JXXL_1xS zQP(@(;p~%!*9J70Rhh8?{SMuB<0{S5 zfz|DbGcyXa^5SB#aw9^c(^+1;#qG2fWjK9)ojb1`y);EXz${Dcf`4M&$SaT(u6T*i zY-l)@AvlBfD{wmCs-muLrHA9O5&(cNN(_LoX);ZqtQZ~&CGE;e%K~Mm3%KLlohvH3 zKY#0!+v50_g}@aDo-H3+7(VUZw&J$udh}WOhrfn@%-vQv4F)!xt1r~-(At^MTqajf_xe9{LAdGh{U49hDKuADHh9Hes0 zRL-@Ka%%b4N^qfc8?$kvWYiEQfgkVz>MBEkq_uH6NC$KjaY|yw`n_MT(Kd!JqZWQV z`*!Vj@J?(9`C{!r357wE0h8f`+w45yiSpUW+b=dwZ}5q!J;DZnnkI3_W zw?8h~#%&T-1(j`DB_l-@V2e{87toqoKj0Vq7E%Dv4TOpi(Eud!fY8}RQ~;fMs}3OE zZw_S6z2^_9oeRrj12%u=TxramDV?ir%IEOdzOKZ4hgA zWs5btY*_q2kuQy>>t3j@I}Q2LxP5yV*f-3>FUx~8_u<`*55bQLfe=`mfzzubrXZ5f zg$lPgPEN(O}g(o9WE3_)P z5)fY?qCyGfju@$c3vMJZ>L*JxHcXxRcz7;f5Wc`2+H=j{Ox(M-28*wZL~hUq=`ejtS&t5n6?sId+Eq(jldRyh~{qMN*4+E+O-Zg0OkfFow9$w8xj2tz3%suyx zz3={U<0njfVAA9%Q>RUzF|%gY>^XBEocGZDhZj7uaM7cSAA7vEZpjl%mo0yC#mc9i zUiHlCHEW-JZr$_i|F~h}rWfirZ+Y>hKW+WjB?0a+nfw$g% z=iP&c-aCBc=&|D`PQHKYFAeO2(;uGsua7?d&wypR^ah zd25gIB$z|6@$Qi;wz7@v5w?)M2}$N#wg^_;TJ{`!k!?b!Kh8b@uF(o`lRty=g4_?B zvCr8**gC9w|4)>5iEUtihWvP#ZDS+YNVbfP0`|ygc7z>cr`QSDa^GkF&Bm|~*k4!! zdzszCeqzhn8Frd|h`9Rifu8pmyN``!_XG279Gk$_vx#gHgP$v#!ltpQY&x64zGE}l zELOv2V}biQY!CY*n}^|^!?^zAz$*X?Gnv4i-&lkFnZ1NJa`hdmlO_a|C|PHbD)8thlI3*y&4yq+6s#P+7Iqwe326v^*CP$Y_Z3K^kiNt3 zF-QxM8j+qsdJKt?vOga`sqH<7w@q7;KDgS3thf~<2etZ!2eUQ)wK+09>`Zo6OBF&B@ z^*imiBke_k{|Q@7zpFvuHMCZ^(qWr$t--~n{>2tIx)dzdg22?Lf zRBw6?^_i&t3x6k3-fA7yJ=L#mQtL+bYn$kJ+q41o&cQLNH$QajzA7>hB69x{vw^ZBAoP+}ja*$`|>x z{DS=qB=Bl&G(%?@i z&tv)UuPH!0a}gxJcC3V9X-rrz%RvD<@^GtAa<nTzso>Po&Uq$UKY~JSWScN+*R#!R3+UQQ>`!bf zsMa>nqgU9gf-VpxAgZv3y$*`<2HOW}xSt(hZ?U&Q8{P%AIKjEg@KLlOPDrQ}3;L;NH;_tPhNyJa*!! zk)tO}9X)yUD7n|P$rH6BOWT!{(`RXc_$(Bk?dh{j94RXj-^;|Oa=b)*SF|>17%%j9 z3;O9e)>S(x&61W&Z%W^3N;M-i^E6Lk)%k<+qw;pGQ9D+?i}TO*7=thQ_N#AyIi-q7P;Pu zHO1Z;yVh-YSGec9566v*`!aq&{Ob5{f-7N8!oGx~o{^phJaavddscZid0zGG_Z;_p z?D^XBv!}&t_QreDy~W;;x1V>A_a5(5?|knQ-nHH>-d)~zyr;aMdB00^B~~VGPrTx* z^KJEg;;-{Mh`e{E7KX^4|=O4o(iv3)Tf!2kV17f^P*+20smc8@yP+ z3#yW#D| zxBGLu#u9T$uacQ14W;F!6{Ukq$CcKUE-GD7y1w+!rF%;cmws6KWm%W9JIltEU2Gq0 zKe;@r{Fd_C@(;>??2y{w)()eD#9+bOug81$fzv zT$X9wqN_H{Y8*4*GR$bQwzmu;bGW;*m+oLoq%lzvycU39j71jZhZuX=&XN@EBXa3J zcIp(AmvjZI283hy8vS?LizAkVfSzshA8f?Jm$<=pMPngng;)IE~5}L!7 zmeQ7%aA{Hd{sjdLnTZV?Hn#&cl4);jY6~!ei`CuO)D~bSJ(MIjHnjzq`9^!FZ9#ix ziGrH<#-_Fav)*VAwJm6mmK2qdnBdz@Ek1 zVEDhWsV%?~>{u4(#-_Fa^W10;wJm7RywTAt`o^ZV04Y)_UVwZcgl7rax4wGevA^GK l>vW0v5lDb-?^_qviv2s|v@MNTdG!IPZ6CGvje*jesGp7Im diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index cb5dd648f..0383c9942 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -35,7 +35,7 @@ - + From f1f9173f2430167024fe93909809987a98cda7e7 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 15 Jan 2013 00:53:32 +0100 Subject: [PATCH 359/916] Prevent closing dialogue window when an answer is expected --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f9d8c3459..8692573b4 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -381,6 +381,10 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { + // Do not close the dialogue window if the player has to answer a question + if (mIsInChoice) + return; + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); // Apply disposition change to NPC's base disposition From 82287445af3d8667fe68e94e1e709becff02d947 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 15 Jan 2013 00:59:48 +0100 Subject: [PATCH 360/916] DialogueWindow: do not execute onFrame() when not visible --- apps/openmw/mwgui/dialogue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index f62bf2a05..c7918ceb7 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -490,7 +490,7 @@ void DialogueWindow::onReferenceUnavailable() void DialogueWindow::onFrame() { - if(mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) { int disp = std::max(0, std::min(100, MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) From 30534404621cdce5ee9c04e027345af2a4a310ae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 15 Jan 2013 12:40:44 +0100 Subject: [PATCH 361/916] Issue #539: fixed AiWander --- apps/openmw/mwscript/aiextensions.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 35243533c..8402a5b4c 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -181,10 +181,14 @@ namespace MWScript runtime.pop(); std::vector idleList; - for (unsigned int i=0; i Date: Tue, 15 Jan 2013 11:10:41 -0800 Subject: [PATCH 362/916] Use typedefs for some maps and some cleanup --- apps/openmw/mwrender/actors.cpp | 124 ++++++++++++++++++-------------- apps/openmw/mwrender/actors.hpp | 18 +++-- 2 files changed, 80 insertions(+), 62 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 05bb030d7..92f5cbe28 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,41 +6,42 @@ #include "renderconst.hpp" -using namespace Ogre; -using namespace MWRender; -using namespace NifOgre; +namespace MWRender +{ Actors::~Actors(){ - std::map::iterator it = mAllActors.begin(); - for (; it != mAllActors.end(); ++it) { + PtrAnimationMap::iterator it = mAllActors.begin(); + for(;it != mAllActors.end();++it) + { delete it->second; it->second = NULL; } } -void Actors::setMwRoot(Ogre::SceneNode* root){ - mMwRoot = root; -} -void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv){ +void Actors::setMwRoot(Ogre::SceneNode* root) +{ mMwRoot = root; } +void Actors::insertNPC(const MWWorld::Ptr &ptr, MWWorld::InventoryStore &inv) +{ insertBegin(ptr, true, true); NpcAnimation* anim = new MWRender::NpcAnimation(ptr, ptr.getRefData ().getBaseNode (), inv, RV_Actors); mAllActors[ptr] = anim; } -void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ + +void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) +{ Ogre::SceneNode* cellnode; - if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) + CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(ptr.getCell()); + if(celliter != mCellSceneNodes.end()) + cellnode = celliter->second; + else { //Create the scenenode and put it in the map cellnode = mMwRoot->createChildSceneNode(); mCellSceneNodes[ptr.getCell()] = cellnode; } - else - { - cellnode = mCellSceneNodes[ptr.getCell()]; - } Ogre::SceneNode* insert = cellnode->createChildSceneNode(); const float *f = ptr.getRefData().getPosition().pos; @@ -51,13 +52,13 @@ void Actors::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_){ f = ptr.getCellRef().mPos.rot; // Rotate around X axis - Quaternion xr(Radian(-f[0]), Vector3::UNIT_X); + Ogre::Quaternion xr(Ogre::Radian(-f[0]), Ogre::Vector3::UNIT_X); // Rotate around Y axis - Quaternion yr(Radian(-f[1]), Vector3::UNIT_Y); + Ogre::Quaternion yr(Ogre::Radian(-f[1]), Ogre::Vector3::UNIT_Y); // Rotate around Z axis - Quaternion zr(Radian(-f[2]), Vector3::UNIT_Z); + Ogre::Quaternion zr(Ogre::Radian(-f[2]), Ogre::Vector3::UNIT_Z); // Rotates first around z, then y, then x insert->setOrientation(xr*yr*zr); @@ -71,30 +72,30 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr){ insertBegin(ptr, true, true); CreatureAnimation* anim = new MWRender::CreatureAnimation(ptr); - //mAllActors.insert(std::pair(ptr,anim)); + delete mAllActors[ptr]; mAllActors[ptr] = anim; - //mAllActors.push_back(&anim);*/ } bool Actors::deleteObject (const MWWorld::Ptr& ptr) { - delete mAllActors[ptr]; - mAllActors.erase(ptr); - if (Ogre::SceneNode *base = ptr.getRefData().getBaseNode()) + delete mAllActors[ptr]; + mAllActors.erase(ptr); + + if(Ogre::SceneNode *base=ptr.getRefData().getBaseNode()) { - Ogre::SceneNode *parent = base->getParentSceneNode(); - - for (std::map::const_iterator iter ( - mCellSceneNodes.begin()); iter!=mCellSceneNodes.end(); ++iter) - if (iter->second==parent) + CellSceneNodeMap::const_iterator iter(mCellSceneNodes.begin()); + for(;iter != mCellSceneNodes.end();++iter) + { + if(iter->second == parent) { base->removeAndDestroyAllChildren(); mRend.getScene()->destroySceneNode (base); ptr.getRefData().setBaseNode (0); return true; } + } return false; } @@ -102,57 +103,70 @@ bool Actors::deleteObject (const MWWorld::Ptr& ptr) return true; } -void Actors::removeCell(MWWorld::Ptr::CellStore* store){ - if(mCellSceneNodes.find(store) != mCellSceneNodes.end()) +void Actors::removeCell(MWWorld::Ptr::CellStore* store) +{ + for(PtrAnimationMap::iterator iter = mAllActors.begin();iter != mAllActors.end();) { - Ogre::SceneNode* base = mCellSceneNodes[store]; - base->removeAndDestroyAllChildren(); - mCellSceneNodes.erase(store); - mRend.getScene()->destroySceneNode(base); - base = 0; - } - for(std::map::iterator iter = mAllActors.begin(); iter != mAllActors.end(); ) - { - if(iter->first.getCell() == store){ + if(iter->first.getCell() == store) + { delete iter->second; mAllActors.erase(iter++); } else ++iter; } + CellSceneNodeMap::iterator celliter = mCellSceneNodes.find(store); + if(celliter != mCellSceneNodes.end()) + { + Ogre::SceneNode *base = celliter->second; + base->removeAndDestroyAllChildren(); + mRend.getScene()->destroySceneNode(base); + mCellSceneNodes.erase(celliter); + } } -void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){ - if(mAllActors.find(ptr) != mAllActors.end()) - mAllActors[ptr]->playGroup(groupName, mode, number); +void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +{ + PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + iter->second->playGroup(groupName, mode, number); } -void Actors::skipAnimation (const MWWorld::Ptr& ptr){ - if(mAllActors.find(ptr) != mAllActors.end()) - mAllActors[ptr]->skipAnim(); +void Actors::skipAnimation (const MWWorld::Ptr& ptr) +{ + PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + iter->second->skipAnim(); } -void Actors::update (float duration){ - for(std::map::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++) +void Actors::update (float duration) +{ + for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++) iter->second->runAnimation(duration); } -void -Actors::updateObjectCell(const MWWorld::Ptr &ptr) +void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { Ogre::SceneNode *node; MWWorld::CellStore *newCell = ptr.getCell(); - if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { + CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell); + if(celliter != mCellSceneNodes.end()) + node = celliter->second; + else + { node = mMwRoot->createChildSceneNode(); mCellSceneNodes[newCell] = node; - } else { - node = mCellSceneNodes[newCell]; } node->addChild(ptr.getRefData().getBaseNode()); - if (mAllActors.find(ptr) != mAllActors.end()) { + + PtrAnimationMap::iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + { /// \note Update key (Ptr's are compared only with refdata so mCell /// on key is outdated), maybe redundant - Animation *anim = mAllActors[ptr]; - mAllActors.erase(ptr); + Animation *anim = iter->second; + mAllActors.erase(iter); mAllActors[ptr] = anim; } } + +} diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 073c5d51f..efb6247e4 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -10,18 +10,22 @@ namespace MWWorld class CellStore; } -namespace MWRender{ - class Actors{ +namespace MWRender +{ + class Actors + { + typedef std::map CellSceneNodeMap; + typedef std::map PtrAnimationMap; + OEngine::Render::OgreRenderer &mRend; - std::map mCellSceneNodes; Ogre::SceneNode* mMwRoot; - std::map mAllActors; + CellSceneNodeMap mCellSceneNodes; + PtrAnimationMap mAllActors; - - - public: + public: Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); + void setMwRoot(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertCreature (const MWWorld::Ptr& ptr); From 8a073c113e277c65fc92598b451de6d336c95244 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Jan 2013 12:07:15 -0800 Subject: [PATCH 363/916] Use const references where appropriate --- apps/openmw/mwbase/soundmanager.hpp | 14 +++++++------- apps/openmw/mwsound/soundmanagerimp.cpp | 16 ++++++++-------- apps/openmw/mwsound/soundmanagerimp.hpp | 18 ++++++++---------- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index 0c706ab49..5d396fac0 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -84,7 +84,7 @@ namespace MWBase ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - virtual void say(MWWorld::Ptr reference, const std::string& filename) = 0; + virtual void say(const MWWorld::Ptr &reference, const std::string& filename) = 0; ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. @@ -92,10 +92,10 @@ namespace MWBase ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const = 0; + virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const = 0; ///< Is actor not speaking? - virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0; + virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()) = 0; ///< Stop an actor speaking virtual SoundPtr playTrack(const MWSound::DecoderPtr& decoder, PlayType type) = 0; @@ -105,14 +105,14 @@ namespace MWBase PlayMode mode=Play_Normal) = 0; ///< Play a sound, independently of 3D-position - virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, + virtual SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal) = 0; ///< Play a sound from an object - virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0; + virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0; ///< Stop the given object from playing the given sound, - virtual void stopSound3D(MWWorld::Ptr reference) = 0; + virtual void stopSound3D(const MWWorld::Ptr &reference) = 0; ///< Stop the given object from playing all sounds. virtual void stopSound(const MWWorld::CellStore *cell) = 0; @@ -121,7 +121,7 @@ namespace MWBase virtual void stopSound(const std::string& soundId) = 0; ///< Stop a non-3d looping sound - virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0; + virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const = 0; ///< Is the given sound currently playing on the given object? virtual void pauseSounds(int types=Play_TypeMask) = 0; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 8a69fc96b..c50290680 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -160,7 +160,7 @@ namespace MWSound return volume; } - bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const + bool SoundManager::isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const { SoundMap::const_iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -229,7 +229,7 @@ namespace MWSound startRandomTitle(); } - void SoundManager::say(MWWorld::Ptr ptr, const std::string& filename) + void SoundManager::say(const MWWorld::Ptr &ptr, const std::string& filename) { if(!mOutput->isInitialized()) return; @@ -269,12 +269,12 @@ namespace MWSound } } - bool SoundManager::sayDone(MWWorld::Ptr ptr) const + bool SoundManager::sayDone(const MWWorld::Ptr &ptr) const { return !isPlaying(ptr, "_say_sound"); } - void SoundManager::stopSay(MWWorld::Ptr ptr) + void SoundManager::stopSay(const MWWorld::Ptr &ptr) { SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -328,7 +328,7 @@ namespace MWSound return sound; } - MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, + MWBase::SoundPtr SoundManager::playSound3D(const MWWorld::Ptr &ptr, const std::string& soundId, float volume, float pitch, PlayMode mode) { MWBase::SoundPtr sound; @@ -356,7 +356,7 @@ namespace MWSound return sound; } - void SoundManager::stopSound3D(MWWorld::Ptr ptr, const std::string& soundId) + void SoundManager::stopSound3D(const MWWorld::Ptr &ptr, const std::string& soundId) { SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -371,7 +371,7 @@ namespace MWSound } } - void SoundManager::stopSound3D(MWWorld::Ptr ptr) + void SoundManager::stopSound3D(const MWWorld::Ptr &ptr) { SoundMap::iterator snditer = mActiveSounds.begin(); while(snditer != mActiveSounds.end()) @@ -418,7 +418,7 @@ namespace MWSound } } - bool SoundManager::getSoundPlaying(MWWorld::Ptr ptr, const std::string& soundId) const + bool SoundManager::getSoundPlaying(const MWWorld::Ptr &ptr, const std::string& soundId) const { return isPlaying(ptr, soundId); } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index b475449d9..2af26d3db 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -14,8 +14,6 @@ #include "../mwbase/soundmanager.hpp" -#include "../mwworld/ptr.hpp" - namespace MWSound { class Sound_Output; @@ -57,7 +55,7 @@ namespace MWSound std::string lookup(const std::string &soundId, float &volume, float &min, float &max); void streamMusicFull(const std::string& filename); - bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const; + bool isPlaying(const MWWorld::Ptr &ptr, const std::string &id) const; void updateSounds(float duration); void updateRegionSound(float duration); @@ -93,7 +91,7 @@ namespace MWSound ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - virtual void say(MWWorld::Ptr reference, const std::string& filename); + virtual void say(const MWWorld::Ptr &reference, const std::string& filename); ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. @@ -101,10 +99,10 @@ namespace MWSound ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const; + virtual bool sayDone(const MWWorld::Ptr &reference=MWWorld::Ptr()) const; ///< Is actor not speaking? - virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); + virtual void stopSay(const MWWorld::Ptr &reference=MWWorld::Ptr()); ///< Stop an actor speaking virtual MWBase::SoundPtr playTrack(const DecoderPtr& decoder, PlayType type); @@ -113,14 +111,14 @@ namespace MWSound virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal); ///< Play a sound, independently of 3D-position - virtual MWBase::SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, + virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId, float volume, float pitch, PlayMode mode=Play_Normal); ///< Play a sound from an object - virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId); + virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId); ///< Stop the given object from playing the given sound, - virtual void stopSound3D(MWWorld::Ptr reference); + virtual void stopSound3D(const MWWorld::Ptr &reference); ///< Stop the given object from playing all sounds. virtual void stopSound(const MWWorld::CellStore *cell); @@ -129,7 +127,7 @@ namespace MWSound virtual void stopSound(const std::string& soundId); ///< Stop a non-3d looping sound - virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; + virtual bool getSoundPlaying(const MWWorld::Ptr &reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? virtual void pauseSounds(int types=Play_TypeMask); From 9e00c6694fac95cf66e360ee3905abd5e59c1814 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 15 Jan 2013 21:40:44 +0100 Subject: [PATCH 364/916] Allow only ID filtered topics for dialogue with creatures --- apps/openmw/mwdialogue/filter.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 7c590c8ef..99be5554a 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -19,12 +19,19 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const { + bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); + // actor id if (!info.mActor.empty()) + { if ( Misc::StringUtils::lowerCase (info.mActor)!=MWWorld::Class::get (mActor).getId (mActor)) return false; - - bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); + } + else if (isCreature) + { + // Creatures must not have topics aside of those specific to their id + return false; + } // NPC race if (!info.mRace.empty()) From e5f040a06f1ec85beb05a547cae8fce1fa4b3815 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Jan 2013 14:10:52 -0800 Subject: [PATCH 365/916] Improve filename pattern matching --- components/bsa/bsa_archive.cpp | 307 +++++++++++---------------------- 1 file changed, 104 insertions(+), 203 deletions(-) diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 9913fb8aa..5274564a6 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -31,150 +31,30 @@ #include "../files/constrainedfiledatastream.hpp" -namespace -{ - using namespace Ogre; -using namespace Bsa; - -struct PathPatternMatcher -{ - PathPatternMatcher (char const * pattern) : pattern (pattern) - { - } - - bool operator () (char const * input) - { - char const * p = pattern; - char const * i = input; - - while (*p && *i) - { - if (*p == '*') - { - ++p; - - while (*i && *i != *p && *i != '/' && *i != '\\') - ++i; - } - else - if (*p == '?') - { - if (*i == '/' || *i == '\\') - break; - - ++i, ++p; - } - if (*p == '/' || *p == '\\') - { - if (*i != '/' && *i != '\\') - break; - - ++i, ++p; - } - else - { - if (*i != *p) - break; - - ++i, ++p; - } - } - - return *p == 0 && *i == 0; - } - -private: - char const * pattern; -}; - -struct FileNameGatherer -{ - StringVectorPtr ptr; - - FileNameGatherer (StringVectorPtr ptr) : ptr (ptr) - { - } - - void operator () (std::string const & filename) const - { - ptr->push_back (filename); - } -}; - -struct FileInfoGatherer -{ - Archive const * archive; - FileInfoListPtr ptr; - - FileInfoGatherer (Archive const * archive, FileInfoListPtr ptr) : - archive (archive), ptr (ptr) - { - } - - void operator () (std::string filename) const - { - FileInfo fi; - - std::size_t pt = filename.rfind ('/'); - if (pt == std::string::npos) - pt = 0; - - fi.archive = const_cast (archive); - fi.path = filename.substr (0, pt); - fi.filename = filename.substr (pt); - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } -}; - -template -void matchFiles (bool recursive, std::string const & pattern, file_iterator begin, file_iterator end, filename_extractor filenameExtractor, match_handler matchHandler) -{ - if (recursive && pattern == "*") - { - for (file_iterator i = begin; i != end; ++i) - matchHandler (filenameExtractor (*i)); - } - else - { - PathPatternMatcher matcher (pattern.c_str ()); - - if (recursive) - { - for (file_iterator i = begin; i != end; ++i) - { - char const * filename = filenameExtractor (*i); - char const * matchable_part = filename; - - for (char const * j = matchable_part; *j; ++j) - { - if (*j == '/' || *j == '\\') - matchable_part = j + 1; - } - - if (matcher (matchable_part)) - matchHandler (filename); - } - } - else - { - for (file_iterator i = begin; i != end; ++i) - { - char const * filename = filenameExtractor (*i); - - if (matcher (filename)) - matchHandler (filename); - } - } - } -} - - static bool fsstrict = false; +static char strict_normalize_char(char ch) +{ + return ch == '\\' ? '/' : ch; +} + +static char nonstrict_normalize_char(char ch) +{ + return ch == '\\' ? '/' : std::tolower(ch); +} + +template +static std::string normalize_path(T1 begin, T2 end) +{ + std::string normalized; + normalized.reserve(std::distance(begin, end)); + char (*normalize_char)(char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char; + std::transform(begin, end, std::back_inserter(normalized), normalize_char); + return normalized; +} + /// An OGRE Archive wrapping a BSAFile archive class DirArchive: public Ogre::Archive { @@ -182,37 +62,12 @@ class DirArchive: public Ogre::Archive index mIndex; - static char strict_normalize_char(char ch) - { - return ch == '\\' ? '/' : ch; - } - - static char nonstrict_normalize_char(char ch) - { - return ch == '\\' ? '/' : std::tolower (ch); - } - - static std::string normalize_path (std::string::const_iterator begin, std::string::const_iterator end) - { - std::string normalized; - normalized.reserve (end-begin); - char (*normalize_char) (char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char; - std::transform (begin, end, std::back_inserter (normalized), normalize_char); - return normalized; - } - index::const_iterator lookup_filename (std::string const & filename) const { std::string normalized = normalize_path (filename.begin (), filename.end ()); - return mIndex.find (normalized); } - static char const * extractFilename (index::value_type const & entry) - { - return entry.first.c_str (); - } - public: DirArchive(const String& name) @@ -273,15 +128,20 @@ public: StringVectorPtr find(const String& pattern, bool recursive = true, bool dirs = false) { - std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); + std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); StringVectorPtr ptr = StringVectorPtr(new StringVector()); - matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, FileNameGatherer (ptr)); + for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();iter++) + { + if(Ogre::StringUtil::match(iter->first, normalizedPattern) || + (recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern))) + ptr->push_back(iter->first); + } return ptr; } bool exists(const String& filename) { - return lookup_filename (filename) != mIndex.end (); + return lookup_filename(filename) != mIndex.end (); } time_t getModifiedTime(const String&) { return 0; } @@ -289,21 +149,44 @@ public: FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, bool dirs = false) const { + std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - FileInfoGatherer gatherer (this, ptr); - std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); - - index::const_iterator i = mIndex.find (normalizedPattern); - - if (i != mIndex.end ()) + index::const_iterator i = mIndex.find(normalizedPattern); + if(i != mIndex.end()) { - gatherer (i->first); + std::string::size_type pt = i->first.rfind('/'); + if(pt == std::string::npos) + pt = 0; + + FileInfo fi; + fi.archive = const_cast(this); + fi.path = i->first.substr(0, pt); + fi.filename = i->first.substr((i->first[pt]=='/') ? pt+1 : pt); + fi.compressedSize = fi.uncompressedSize = 0; + + ptr->push_back(fi); } else { + for(index::const_iterator iter = mIndex.begin();iter != mIndex.end();iter++) + { + if(Ogre::StringUtil::match(iter->first, normalizedPattern) || + (recursive && Ogre::StringUtil::match(iter->first, "*/"+normalizedPattern))) + { + std::string::size_type pt = iter->first.rfind('/'); + if(pt == std::string::npos) + pt = 0; - matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, gatherer); + FileInfo fi; + fi.archive = const_cast(this); + fi.path = iter->first.substr(0, pt); + fi.filename = iter->first.substr((iter->first[pt]=='/') ? pt+1 : pt); + fi.compressedSize = fi.uncompressedSize = 0; + + ptr->push_back(fi); + } + } } return ptr; @@ -312,9 +195,9 @@ public: class BSAArchive : public Archive { - BSAFile arc; + Bsa::BSAFile arc; - static char const * extractFilename (BSAFile::FileStruct const & entry) + static const char *extractFilename(const Bsa::BSAFile::FileStruct &entry) { return entry.name; } @@ -330,13 +213,13 @@ public: void load() {} void unload() {} - DataStreamPtr open(const String& filename, bool recursive = true) const + DataStreamPtr open(const String& filename, bool readonly = true) const { // Get a non-const reference to arc. This is a hack and it's all // OGRE's fault. You should NOT expect an open() command not to // have any side effects on the archive, and hence this function // should not have been declared const in the first place. - BSAFile *narc = const_cast(&arc); + Bsa::BSAFile *narc = const_cast(&arc); // Open the file return narc->getFile(filename.c_str()); @@ -360,32 +243,51 @@ public: return findFileInfo ("*", recursive, dirs); } - // After load() is called, find("*") is called once. It doesn't seem - // to matter that we return an empty list, exists() gets called on - // the correct files anyway. - StringVectorPtr find(const String& pattern, bool recursive = true, - bool dirs = false) - { + StringVectorPtr find(const String& pattern, bool recursive = true, + bool dirs = false) + { + std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); + const Bsa::BSAFile::FileList &filelist = arc.getList(); StringVectorPtr ptr = StringVectorPtr(new StringVector()); - matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileNameGatherer (ptr)); + for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();iter++) + { + std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name)); + if(Ogre::StringUtil::match(ent, normalizedPattern) || + (recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern))) + ptr->push_back(iter->name); + } return ptr; - } + } - /* Gets called once for each of the ogre formats, *.program, - *.material etc. We ignore all these. + FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, + bool dirs = false) const + { + std::string normalizedPattern = normalize_path(pattern.begin(), pattern.end()); + FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); + const Bsa::BSAFile::FileList &filelist = arc.getList(); - However, it's also called by MyGUI to find individual textures, - and we can't ignore these since many of the GUI textures are - located in BSAs. So instead we channel it through exists() and - set up a single-element result list if the file is found. - */ - FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, - bool dirs = false) const - { - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileInfoGatherer (this, ptr)); - return ptr; - } + for(Bsa::BSAFile::FileList::const_iterator iter = filelist.begin();iter != filelist.end();iter++) + { + std::string ent = normalize_path(iter->name, iter->name+std::strlen(iter->name)); + if(Ogre::StringUtil::match(ent, normalizedPattern) || + (recursive && Ogre::StringUtil::match(ent, "*/"+normalizedPattern))) + { + std::string::size_type pt = ent.rfind('/'); + if(pt == std::string::npos) + pt = 0; + + FileInfo fi; + fi.archive = const_cast(this); + fi.path = std::string(iter->name, pt); + fi.filename = std::string(iter->name + ((ent[pt]=='/') ? pt+1 : pt)); + fi.compressedSize = fi.uncompressedSize = iter->fileSize; + + ptr->push_back(fi); + } + } + + return ptr; + } }; // An archive factory for BSA archives @@ -445,7 +347,6 @@ static void insertDirFactory() } } -} namespace Bsa { From 3220330ce0e0bcaf7899ed1492563330f79f0e91 Mon Sep 17 00:00:00 2001 From: Thoronador Date: Wed, 16 Jan 2013 04:19:16 +0100 Subject: [PATCH 366/916] fix spelling in comment --- apps/openmw/mwscript/userextensions.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/userextensions.hpp b/apps/openmw/mwscript/userextensions.hpp index 3642eb5f4..4bc3b46ec 100644 --- a/apps/openmw/mwscript/userextensions.hpp +++ b/apps/openmw/mwscript/userextensions.hpp @@ -13,7 +13,7 @@ namespace Interpreter namespace MWScript { - /// \brief Temporaty script functionality limited to the console + /// \brief Temporary script functionality limited to the console namespace User { void registerExtensions (Compiler::Extensions& extensions); From df602553d10fa69ed4ab6a4902daaefed276749d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 16 Jan 2013 09:13:36 +0100 Subject: [PATCH 367/916] Reworked MWRender::Water to be more OOP-ish and possibly allow other reflection types. --- apps/openmw/mwrender/water.cpp | 270 +++++++++++++++++++++------------ apps/openmw/mwrender/water.hpp | 77 ++++++++-- 2 files changed, 238 insertions(+), 109 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 04a126367..27b9fc679 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -24,12 +24,163 @@ using namespace Ogre; namespace MWRender { +CubeReflection::CubeReflection(Ogre::SceneManager* sceneManager) + : Reflection(sceneManager) +{ + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().createManual("CubeReflection", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_CUBE_MAP, + 512,512, 0, PF_R8G8B8, TU_RENDERTARGET); + + mCamera = mSceneMgr->createCamera ("CubeCamera"); + mCamera->setNearClipDistance (5); + mCamera->setFarClipDistance (1000); + + for (int face = 0; face < 6; ++face) + { + mRenderTargets[face] = texture->getBuffer (face)->getRenderTarget(); + mRenderTargets[face]->removeAllViewports (); + Viewport* vp = mRenderTargets[face]->addViewport (mCamera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setMaterialScheme ("water_reflection"); + mRenderTargets[face]->setAutoUpdated(false); + + /* + Vector3 lookAt(0,0,0), up(0,0,0), right(0,0,0); + switch(face) + { + case 0: lookAt.x =-1; up.y = 1; right.z = 1; break; // +X + case 1: lookAt.x = 1; up.y = 1; right.z =-1; break; // -X + case 2: lookAt.y =-1; up.z = 1; right.x = 1; break; // +Y + case 3: lookAt.y = 1; up.z =-1; right.x = 1; break; // -Y + case 4: lookAt.z = 1; up.y = 1; right.x =-1; break; // +Z + case 5: lookAt.z =-1; up.y = 1; right.x =-1; break; // -Z + } + Quaternion orient(right, up, lookAt); + mCamera->setOrientation(orient); + */ + } +} + +CubeReflection::~CubeReflection () +{ + Ogre::TextureManager::getSingleton ().remove("CubeReflection"); + mSceneMgr->destroyCamera (mCamera); +} + +void CubeReflection::update () +{ + mParentCamera->getParentSceneNode ()->needUpdate (); + mCamera->setPosition(mParentCamera->getDerivedPosition()); +} + +// -------------------------------------------------------------------------------------------------------------------------------- + +PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) + : Reflection(sceneManager) + , mSky(sky) +{ + mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); + mSceneMgr->addRenderQueueListener(this); + + mTexture = TextureManager::getSingleton().createManual("WaterReflection", + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_A8R8G8B8, TU_RENDERTARGET); + + mRenderTarget = mTexture->getBuffer()->getRenderTarget(); + Viewport* vp = mRenderTarget->addViewport(mCamera); + vp->setOverlaysEnabled(false); + vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); + vp->setShadowsEnabled(false); + // use fallback techniques without shadows and without mrt + vp->setMaterialScheme("water_reflection"); + mRenderTarget->addListener(this); + mRenderTarget->setActive(true); + + sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName()); +} + +PlaneReflection::~PlaneReflection () +{ + mRenderTarget->removeListener (this); + mSceneMgr->destroyCamera (mCamera); + TextureManager::getSingleton ().remove("WaterReflection"); +} + +void PlaneReflection::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) +{ + // We don't want the sky to get clipped by custom near clip plane (the water plane) + if (queueGroupId < 20 && mRenderActive) + { + mCamera->disableCustomNearClipPlane(); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + } +} + +void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) +{ + if (queueGroupId < 20 && mRenderActive) + { + if (!mIsUnderwater) + mCamera->enableCustomNearClipPlane(mErrorPlane); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + } +} + +void PlaneReflection::preRenderTargetUpdate(const RenderTargetEvent& evt) +{ + mParentCamera->getParentSceneNode ()->needUpdate (); + mCamera->setOrientation(mParentCamera->getDerivedOrientation()); + mCamera->setPosition(mParentCamera->getDerivedPosition()); + mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); + mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); + mCamera->setAspectRatio(mParentCamera->getAspectRatio()); + mCamera->setFOVy(mParentCamera->getFOVy()); + mRenderActive = true; + + Vector3 pos = mParentCamera->getRealPosition(); + pos.y = (mWaterPlane).d*2 - pos.y; + mSky->setSkyPosition(pos); + mCamera->enableReflection(mWaterPlane); +} + +void PlaneReflection::postRenderTargetUpdate(const RenderTargetEvent& evt) +{ + mSky->resetSkyPosition(); + mCamera->disableReflection(); + mCamera->disableCustomNearClipPlane(); + mRenderActive = false; +} + +void PlaneReflection::setWaterPlane (Plane plane) +{ + mWaterPlane = plane; + mErrorPlane = Plane(plane.normal, mWaterPlane.d - 5); +} + +void PlaneReflection::setActive (bool active) +{ + mRenderTarget->setActive(active); +} + +void PlaneReflection::setViewportBackground(Ogre::ColourValue colour) +{ + mRenderTarget->getViewport (0)->setBackgroundColour (colour); +} + +void PlaneReflection::setVisibilityMask (int flags) +{ + mRenderTarget->getViewport (0)->setVisibilityMask (flags); +} + +// -------------------------------------------------------------------------------------------------------------------------------- + Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell) : - mCamera (camera), mSceneManager (camera->getSceneManager()), + mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), - mReflectionTarget(0), mActive(1), mToggled(1), - mReflectionRenderActive(false), mRendering(rend), - mWaterTimer(0.f) + mActive(1), mToggled(1), + mRendering(rend), + mWaterTimer(0.f), + mReflection(NULL) { mSky = rend->getSkyManager(); @@ -43,13 +194,11 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z); - mWater = mSceneManager->createEntity("water"); + mWater = mSceneMgr->createEntity("water"); mWater->setVisibilityFlags(RV_Water); mWater->setCastShadows(false); - mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); - - mReflectionCamera = mSceneManager->createCamera("ReflectionCamera"); + mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); if(!(cell->mData.mFlags & cell->Interior)) { @@ -72,8 +221,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel underwaterDome->setMaterialName("Underwater_Dome"); */ - mSceneManager->addRenderQueueListener(this); - assignTextures(); setHeight(mTop); @@ -142,12 +289,9 @@ Water::~Water() { MeshManager::getSingleton().remove("water"); - if (mReflectionTarget) - mReflectionTexture->getBuffer()->getRenderTarget()->removeListener(this); - mWaterNode->detachObject(mWater); - mSceneManager->destroyEntity(mWater); - mSceneManager->destroySceneNode(mWaterNode); + mSceneMgr->destroyEntity(mWater); + mSceneMgr->destroySceneNode(mWaterNode); } void Water::changeCell(const ESM::Cell* cell) @@ -166,8 +310,8 @@ void Water::setHeight(const float height) mWaterPlane = Plane(Vector3::UNIT_Y, height); - // small error due to reflection texture size & reflection distortion - mErrorPlane = Plane(Vector3::UNIT_Y, height - 5); + if (mReflection) + mReflection->setWaterPlane(mWaterPlane); mWaterNode->setPosition(0, height, 0); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); @@ -190,6 +334,9 @@ Water::updateUnderwater(bool underwater) mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID; + if (mReflection) + mReflection->setUnderwater (mIsUnderwater); + updateVisible(); } @@ -198,37 +345,6 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); } -void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) -{ - if (evt.source == mReflectionTarget) - { - mCamera->getParentSceneNode ()->needUpdate (); - mReflectionCamera->setOrientation(mCamera->getDerivedOrientation()); - mReflectionCamera->setPosition(mCamera->getDerivedPosition()); - mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance()); - mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); - mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); - mReflectionCamera->setFOVy(mCamera->getFOVy()); - mReflectionRenderActive = true; - - Vector3 pos = mCamera->getRealPosition(); - pos.y = mTop*2 - pos.y; - mSky->setSkyPosition(pos); - mReflectionCamera->enableReflection(mWaterPlane); - } -} - -void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) -{ - if (evt.source == mReflectionTarget) - { - mSky->resetSkyPosition(); - mReflectionCamera->disableReflection(); - mReflectionCamera->disableCustomNearClipPlane(); - mReflectionRenderActive = false; - } -} - void Water::assignTextures() { if (Settings::Manager::getBool("shader", "Water")) @@ -246,34 +362,16 @@ void Water::assignTextures() void Water::setViewportBackground(const ColourValue& bg) { - if (mReflectionTarget) - mReflectionTarget->getViewport(0)->setBackgroundColour(bg); + if (mReflection) + mReflection->setViewportBackground(bg); } void Water::updateVisible() { mWater->setVisible(mToggled && mActive); - if (mReflectionTarget) - mReflectionTarget->setActive(mToggled && mActive); -} - -void Water::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) -{ - // We don't want the sky to get clipped by custom near clip plane (the water plane) - if (queueGroupId < 20 && mReflectionRenderActive) + if (mReflection) { - mReflectionCamera->disableCustomNearClipPlane(); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); - } -} - -void Water::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) -{ - if (queueGroupId < 20 && mReflectionRenderActive) - { - if (!mIsUnderwater) - mReflectionCamera->enableCustomNearClipPlane(mErrorPlane); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); + mReflection->setActive(mToggled && mActive); } } @@ -293,10 +391,10 @@ void Water::update(float dt) void Water::applyRTT() { - if (mReflectionTarget) + if (mReflection) { - TextureManager::getSingleton().remove("WaterReflection"); - mReflectionTarget = 0; + delete mReflection; + mReflection = NULL; } // Create rendertarget for reflection @@ -304,23 +402,9 @@ void Water::applyRTT() if (Settings::Manager::getBool("shader", "Water")) { - mReflectionTexture = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_A8R8G8B8, TU_RENDERTARGET); - - RenderTarget* rtt = mReflectionTexture->getBuffer()->getRenderTarget(); - Viewport* vp = rtt->addViewport(mReflectionCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); - vp->setShadowsEnabled(false); - // use fallback techniques without shadows and without mrt - vp->setMaterialScheme("water_reflection"); - rtt->addListener(this); - rtt->setActive(true); - - mReflectionTarget = rtt; - - sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mReflectionTexture->getName()); - + mReflection = new PlaneReflection(mSceneMgr, mSky); + mReflection->setParentCamera (mCamera); + mReflection->setWaterPlane(mWaterPlane); mWater->setRenderQueueGroup(RQG_Water); } else @@ -336,10 +420,8 @@ void Water::applyVisibilityMask() + RV_Misc * Settings::Manager::getBool("reflect misc", "Water") + RV_Sky; - if (mReflectionTarget) - { - mReflectionTexture->getBuffer()->getRenderTarget()->getViewport(0)->setVisibilityMask(mVisibilityFlags); - } + if (mReflection) + mReflection->setVisibilityMask(mVisibilityFlags); } void Water::processChangedSettings(const Settings::CategorySettingVector& settings) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index f1e3d7a3b..de78542b7 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,15 +30,73 @@ namespace MWRender { class SkyManager; class RenderingManager; + class Reflection + { + public: + Reflection(Ogre::SceneManager* sceneManager) + : mSceneMgr(sceneManager) {} + + virtual void setWaterPlane (Ogre::Plane plane) {} + virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } + void setUnderwater(bool underwater) { mIsUnderwater = underwater; } + virtual void setActive (bool active) {} + virtual void setViewportBackground(Ogre::ColourValue colour) {} + virtual void update() {} + virtual void setVisibilityMask (int flags) {} + + protected: + Ogre::Camera* mCamera; + Ogre::Camera* mParentCamera; + Ogre::TexturePtr mTexture; + Ogre::SceneManager* mSceneMgr; + bool mIsUnderwater; + }; + + class CubeReflection : public Reflection + { + public: + CubeReflection(Ogre::SceneManager* sceneManager); + virtual ~CubeReflection(); + + virtual void update(); + protected: + Ogre::RenderTarget* mRenderTargets[6]; + }; + + class PlaneReflection : public Reflection, public Ogre::RenderQueueListener, public Ogre::RenderTargetListener + { + public: + PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky); + virtual ~PlaneReflection(); + + virtual void setWaterPlane (Ogre::Plane plane); + virtual void setActive (bool active); + virtual void setVisibilityMask (int flags); + + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + + void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); + void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); + + virtual void setViewportBackground(Ogre::ColourValue colour); + + protected: + Ogre::RenderTarget* mRenderTarget; + SkyManager* mSky; + Ogre::Plane mWaterPlane; + Ogre::Plane mErrorPlane; + bool mRenderActive; + }; + /// Water rendering class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener, public sh::MaterialInstanceListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; - Ogre::SceneManager *mSceneManager; + Ogre::SceneManager *mSceneMgr; Ogre::Plane mWaterPlane; - Ogre::Plane mErrorPlane; Ogre::SceneNode *mWaterNode; Ogre::Entity *mWater; @@ -52,17 +110,9 @@ namespace MWRender { float mWaterTimer; - bool mReflectionRenderActive; - Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); protected: - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - - void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); - void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); - void applyRTT(); void applyVisibilityMask(); @@ -75,14 +125,11 @@ namespace MWRender { Ogre::MaterialPtr mMaterial; - Ogre::Camera* mReflectionCamera; - - Ogre::TexturePtr mReflectionTexture; - Ogre::RenderTarget* mReflectionTarget; - bool mUnderwaterEffect; int mVisibilityFlags; + Reflection* mReflection; + public: Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); ~Water(); From 3c02e1ccc9f82a7ede31a0634a5688aec359216a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 08:22:38 -0800 Subject: [PATCH 368/916] Run physics right after updating the actors --- apps/openmw/engine.cpp | 6 +----- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +-- apps/openmw/mwmechanics/actors.cpp | 6 ++++-- apps/openmw/mwmechanics/actors.hpp | 3 +-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 5 ++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 3 +-- 6 files changed, 10 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e6296ab96..b1554fc75 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -96,13 +96,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWorld()->markCellAsUnchanged(); // update actors - std::vector > movement; - MWBase::Environment::get().getMechanicsManager()->update (movement, mEnvironment.getFrameDuration(), + MWBase::Environment::get().getMechanicsManager()->update(mEnvironment.getFrameDuration(), MWBase::Environment::get().getWindowManager()->isGuiMode()); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->doPhysics (movement, mEnvironment.getFrameDuration()); - // update world MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode()); diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index a1023c986..55eb729a4 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -52,8 +52,7 @@ namespace MWBase ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - virtual void update (std::vector >& movement, - float duration, bool paused) = 0; + virtual void update (float duration, bool paused) = 0; ///< Update actor stats and store desired velocity vectors in \a movement /// /// \param paused In game type does not currently advance (this usually means some GUI diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4eae6e213..485d7448b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -193,8 +193,7 @@ namespace MWMechanics } } - void Actors::update (std::vector >& movement, float duration, - bool paused) + void Actors::update (float duration, bool paused) { mDuration += duration; @@ -257,12 +256,15 @@ namespace MWMechanics } } + std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } + if (!paused) + MWBase::Environment::get().getWorld()->doPhysics (movement, duration); } void Actors::restoreDynamicStats() diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index f1e5ab437..faf21a12f 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -56,8 +56,7 @@ namespace MWMechanics void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. - void update (std::vector >& movement, - float duration, bool paused); + void update (float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement void updateActor (const MWWorld::Ptr& ptr, float duration); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index dae417d44..3b57c3485 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -201,8 +201,7 @@ namespace MWMechanics mWatched = ptr; } - void MechanicsManager::update (std::vector >& movement, - float duration, bool paused) + void MechanicsManager::update (float duration, bool paused) { if (!mWatched.isEmpty()) { @@ -298,7 +297,7 @@ namespace MWMechanics winMgr->configureSkills (majorSkills, minorSkills); } - mActors.update (movement, duration, paused); + mActors.update (duration, paused); } void MechanicsManager::restoreDynamicStats() diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index d3a97db36..0efe12f32 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -54,8 +54,7 @@ namespace MWMechanics ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - virtual void update (std::vector >& movement, - float duration, bool paused); + virtual void update (float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement /// /// \param paused In game type does not currently advance (this usually means some GUI From c1b32d6006adb35d989808e6eb2248cce431409f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 08:24:20 -0800 Subject: [PATCH 369/916] Remove outdated comments --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 -- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 55eb729a4..401e360d7 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -39,8 +39,6 @@ namespace MWBase virtual void addActor (const MWWorld::Ptr& ptr) = 0; ///< Register an actor for stats management - /// - /// \note Dead actors are ignored. virtual void removeActor (const MWWorld::Ptr& ptr) = 0; ///< Deregister an actor for stats management diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 0efe12f32..549807285 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -41,8 +41,6 @@ namespace MWMechanics virtual void addActor (const MWWorld::Ptr& ptr); ///< Register an actor for stats management - /// - /// \note Dead actors are ignored. virtual void removeActor (const MWWorld::Ptr& ptr); ///< Deregister an actor for stats management From 63e685ea39d30fc2892166841c7776553a0548d5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 09:59:19 -0800 Subject: [PATCH 370/916] Add a method to get the Animation from a Ptr --- apps/openmw/mwbase/world.hpp | 4 ++++ apps/openmw/mwrender/actors.cpp | 8 ++++++++ apps/openmw/mwrender/actors.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 8 ++++++++ apps/openmw/mwrender/renderingmanager.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 4 ++++ 7 files changed, 34 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index b8557368d..f846c51ba 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -36,6 +36,7 @@ namespace ESM namespace MWRender { class ExternalRendering; + class Animation; } namespace MWWorld @@ -308,6 +309,9 @@ namespace MWBase /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; + /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void stopVideo() = 0; diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index c36248aaf..10b654834 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -145,6 +145,14 @@ void Actors::update (float duration) iter->second->runAnimation(duration); } +Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) +{ + PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); + if(iter != mAllActors.end()) + return iter->second; + return NULL; +} + void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { Ogre::SceneNode *node; diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 53829000c..92965a059 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -54,6 +54,8 @@ namespace MWRender /// Updates containing cell for object rendering data void updateObjectCell(const MWWorld::Ptr &ptr); + + Animation* getAnimation(const MWWorld::Ptr &ptr); }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fdad152e6..d1f0b17aa 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -929,6 +929,14 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend rendering.setup (mRendering.getScene()); } +Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) +{ + Animation *anim = mActors.getAnimation(ptr); + // TODO: Check mObjects too. + return anim; +} + + void RenderingManager::playVideo(const std::string& name, bool allowSkipping) { mVideoPlayer->playVideo ("video/" + name, allowSkipping); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 68f2d79c3..1a7d213f3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -46,6 +46,7 @@ namespace MWRender class ExternalRendering; class GlobalMap; class VideoPlayer; + class Animation; class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { @@ -196,6 +197,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setupExternalRendering (MWRender::ExternalRendering& rendering); + Animation* getAnimation(const MWWorld::Ptr &ptr); + void playVideo(const std::string& name, bool allowSkipping); void stopVideo(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f49b4bf9b..b855bab8f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1374,6 +1374,11 @@ namespace MWWorld } + MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) + { + return mRendering->getAnimation(ptr); + } + void World::playVideo (const std::string &name, bool allowSkipping) { mRendering->playVideo(name, allowSkipping); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7e89c1d87..f622144b2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -37,6 +37,7 @@ namespace MWRender { class SkyManager; class CellRender; + class Animation; } namespace MWWorld @@ -352,6 +353,9 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); + /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping); virtual void stopVideo(); From b378bc92a06422c55290be5cb9dbac6f295b145a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 10:16:37 -0800 Subject: [PATCH 371/916] Store an animation object in the character controller --- apps/openmw/mwmechanics/actors.cpp | 5 +++-- apps/openmw/mwmechanics/character.hpp | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 485d7448b..bd7a9cef2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -165,11 +165,12 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else { - mActors.insert(std::make_pair(ptr, CharacterController(ptr, CharState_Dead))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 206f6e737..8a0986117 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -3,6 +3,11 @@ #include "../mwworld/ptr.hpp" +namespace MWRender +{ + class Animation; +} + namespace MWMechanics { @@ -14,12 +19,13 @@ enum CharacterState { class CharacterController { MWWorld::Ptr mPtr; + MWRender::Animation *mAnimation; CharacterState mState; public: - CharacterController(const MWWorld::Ptr &ptr, CharacterState state) - : mPtr(ptr), mState(state) + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) + : mPtr(ptr), mAnimation(anim), mState(state) { } CharacterState getState() const From 3c487e601934b7422da4683fe5953d99298da7ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 10:45:18 -0800 Subject: [PATCH 372/916] Play an animation when changing states --- apps/openmw/mwmechanics/actors.cpp | 4 ---- apps/openmw/mwmechanics/character.cpp | 33 +++++++++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 8 ++----- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bd7a9cef2..d9a3b6878 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,10 +169,7 @@ namespace MWMechanics if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else - { mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, "death1", 2); - } } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -247,7 +244,6 @@ namespace MWMechanics } iter->second.setState(CharState_Dead); - MWBase::Environment::get().getWorld()->playAnimationGroup(iter->first, "death1", 0); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 319c4fe9b..6d5b92860 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,8 +19,41 @@ #include "character.hpp" +#include "../mwrender/animation.hpp" namespace MWMechanics { +CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) + : mPtr(ptr), mAnimation(anim), mState(state) +{ + if(!mAnimation) + return; + + switch(mState) + { + case CharState_Idle: + mAnimation->playGroup("idle", 1, 1); + break; + case CharState_Dead: + mAnimation->playGroup("death1", 1, 1); + break; + } +} + + +void CharacterController::setState(CharacterState state) +{ + mState = state; + switch(mState) + { + case CharState_Idle: + mAnimation->playGroup("idle", 1, 1); + break; + case CharState_Dead: + mAnimation->playGroup("death1", 1, 1); + break; + } +} + } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8a0986117..9bb3a1bfc 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -24,15 +24,11 @@ class CharacterController CharacterState mState; public: - CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state) - { } + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); + void setState(CharacterState state); CharacterState getState() const { return mState; } - - void setState(CharacterState state) - { mState = state; } }; } From f46587c3836d040809cd6105b3a9ef3f5b45f7ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 11:01:08 -0800 Subject: [PATCH 373/916] Store an character controller in the animation --- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/animation.cpp | 6 ++++++ apps/openmw/mwrender/animation.hpp | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6d5b92860..21ebd255a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,6 +30,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; + mAnimation->setController(this); switch(mState) { case CharState_Idle: diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b8016d087..4f32de364 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -95,6 +95,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +void Animation::setController(MWMechanics::CharacterController *controller) +{ + mController = controller; +} + + void Animation::updatePosition(float time) { mCurGroup.mAnimState->setTimePosition(time); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 859d2b989..ed9e4f585 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -5,6 +5,11 @@ #include "../mwworld/ptr.hpp" +namespace MWMechanics +{ + class CharacterController; +} + namespace MWRender { @@ -26,8 +31,9 @@ class Animation protected: MWWorld::Ptr mPtr; - Ogre::SceneNode* mInsert; + MWMechanics::CharacterController *mController; + Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; Ogre::Bone *mAccumRoot; @@ -56,6 +62,7 @@ public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); + void setController(MWMechanics::CharacterController *controller); void playGroup(std::string groupname, int mode, int loops); void skipAnim(); virtual void runAnimation(float timepassed); From 0a2f92f67901c06c80d9750cf40b197fd173a51d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 11:57:08 -0800 Subject: [PATCH 374/916] Keep track of the current text key in the animation --- apps/openmw/mwrender/animation.cpp | 27 +++++++++++++++++++++++++-- apps/openmw/mwrender/animation.hpp | 7 +++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4f32de364..69bd01e2b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -130,6 +130,11 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + + mCurGroup.mNext = mCurGroup.mStart; + while(mCurGroup.mNext->first < time) + mCurGroup.mNext++; + if(mNonAccumRoot) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); @@ -141,7 +146,8 @@ void Animation::resetPosition(float time) bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) { - const NifOgre::TextKeyMap &textkeys = mTextKeys[groupname]; + times->mTextKeys = &mTextKeys[groupname]; + const NifOgre::TextKeyMap &textkeys = *times->mTextKeys; if(textkeys.size() == 0) return false; @@ -202,6 +208,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) std::cerr<< e.what() < 0) mNextGroup = times; @@ -211,7 +218,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(); - mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart)->first; + mTime = mCurGroup.mNext->first; mCurGroup.mAnimState->setEnabled(true); resetPosition(mTime); } @@ -230,6 +237,12 @@ void Animation::runAnimation(float timepassed) recheck: if(mTime >= mCurGroup.mLoopStop->first) { + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) + { + mCurGroup.mNext++; + } + if(mCurGroup.mLoops > 1) { mCurGroup.mLoops--; @@ -240,6 +253,11 @@ void Animation::runAnimation(float timepassed) } else if(mTime >= mCurGroup.mStop->first) { + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mCurGroup.mStop->first) + { + mCurGroup.mNext++; + } if(mNextGroup.mLoops > 0) { updatePosition(mCurGroup.mStop->first); @@ -254,6 +272,11 @@ void Animation::runAnimation(float timepassed) mTime = mCurGroup.mStop->first; } } + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= mTime) + { + mCurGroup.mNext++; + } updatePosition(mTime); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ed9e4f585..43cce0c02 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,16 +16,19 @@ namespace MWRender class Animation { struct GroupTimes { + NifOgre::TextKeyMap *mTextKeys; + NifOgre::TextKeyMap::const_iterator mStart; NifOgre::TextKeyMap::const_iterator mStop; NifOgre::TextKeyMap::const_iterator mLoopStart; NifOgre::TextKeyMap::const_iterator mLoopStop; + NifOgre::TextKeyMap::const_iterator mNext; + Ogre::AnimationState *mAnimState; size_t mLoops; - GroupTimes() - : mAnimState(NULL), mLoops(0) + GroupTimes() : mTextKeys(NULL), mAnimState(NULL), mLoops(0) { } }; From d2fc3c7b333f7dedd605b073dcd5a22eb853e3b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 13:09:21 -0800 Subject: [PATCH 375/916] Add a method to tell the character controller of new text keys --- apps/openmw/mwmechanics/character.cpp | 21 +++++++++++++++++++++ apps/openmw/mwmechanics/character.hpp | 7 +++++++ apps/openmw/mwrender/animation.cpp | 9 +++++++++ 3 files changed, 37 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21ebd255a..6496ba9f2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,7 @@ #include "../mwrender/animation.hpp" + namespace MWMechanics { @@ -42,6 +43,26 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } } +CharacterController::CharacterController(const CharacterController &rhs) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) +{ + if(!mAnimation) + return; + /* We've been copied. Update the animation with the new controller. */ + mAnimation->setController(this); +} + + +void CharacterController::markerEvent(const std::string &evt) +{ + std::string::size_type gp = evt.find(':'); + if(gp >= evt.length()-2) + { + std::cerr<< "Unexpected animation marker: \""<end() && mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } @@ -256,6 +261,8 @@ void Animation::runAnimation(float timepassed) while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first <= mCurGroup.mStop->first) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } if(mNextGroup.mLoops > 0) @@ -275,6 +282,8 @@ void Animation::runAnimation(float timepassed) while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first <= mTime) { + if(mController) + mController->markerEvent(mCurGroup.mNext->second); mCurGroup.mNext++; } From 94b93227d32a9753447985a1fbc78af3c8c7230a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 14:37:32 -0800 Subject: [PATCH 376/916] Treat activators as actors for rendering and mechanics Kinda hacky, but it's the only way to get animated activators (flags, silt striders, etc) to work properly. --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwclass/activator.cpp | 9 +-- apps/openmw/mwmechanics/actors.cpp | 14 ++++- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/activatoranimation.cpp | 64 +++++++++++++++++++++ apps/openmw/mwrender/activatoranimation.hpp | 23 ++++++++ apps/openmw/mwrender/actors.cpp | 8 +++ apps/openmw/mwrender/actors.hpp | 3 +- apps/openmw/mwrender/animation.cpp | 3 + 9 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 apps/openmw/mwrender/activatoranimation.cpp create mode 100644 apps/openmw/mwrender/activatoranimation.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 563c9e422..ec7700bee 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -14,8 +14,8 @@ set(GAME_HEADER source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender - renderingmanager debugging sky player animation npcanimation creatureanimation actors objects - renderinginterface localmap occlusionquery terrain terrainmaterial water shadows + renderingmanager debugging sky player animation npcanimation creatureanimation activatoranimation + actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows compositors characterpreview externalrendering globalmap videoplayer ) diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 26d286aa1..292627286 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -5,12 +5,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld//cellstore.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/physicssystem.hpp" -#include "../mwrender/objects.hpp" +#include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwgui/tooltips.hpp" @@ -21,9 +22,8 @@ namespace MWClass { const std::string model = getModel(ptr); if (!model.empty()) { - MWRender::Objects& objects = renderingInterface.getObjects(); - objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, model); + MWRender::Actors& actors = renderingInterface.getActors(); + actors.insertActivator(ptr); } } @@ -32,6 +32,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addObject(ptr); + MWBase::Environment::get().getMechanicsManager()->addActor(ptr); } std::string Activator::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index d9a3b6878..23272e674 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,7 +166,9 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) + /* Kind of a hack. Activators need a character controller to manage an idle state. */ + if(ptr.getTypeName() == typeid(ESM::Activator).name() || + !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); @@ -203,6 +205,11 @@ namespace MWMechanics PtrControllerMap::iterator iter(mActors.begin()); while(iter != mActors.end()) { + if(iter->first.getTypeName() == typeid(ESM::Activator).name()) + { + iter++; + continue; + } if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) @@ -267,7 +274,10 @@ namespace MWMechanics void Actors::restoreDynamicStats() { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - calculateRestoration(iter->first, 3600); + { + if(iter->first.getTypeName() != typeid(ESM::Activator).name()) + calculateRestoration(iter->first, 3600); + } } int Actors::countDeaths (const std::string& id) const diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6496ba9f2..5bf468ffb 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,7 @@ #include "../mwrender/animation.hpp" +#include "../mwworld/class.hpp" namespace MWMechanics { diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp new file mode 100644 index 000000000..18ae31865 --- /dev/null +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -0,0 +1,64 @@ +#include "activatoranimation.hpp" + +#include +#include +#include + +#include "renderconst.hpp" + +#include "../mwbase/world.hpp" + +namespace MWRender +{ + +ActivatorAnimation::~ActivatorAnimation() +{ +} + +ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) + : Animation(ptr) +{ + MWWorld::LiveCellRef *ref = mPtr.get(); + + assert (ref->mBase != NULL); + if(!ref->mBase->mModel.empty()) + { + std::string mesh = "meshes\\" + ref->mBase->mModel; + + createEntityList(mPtr.getRefData().getBaseNode(), mesh); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) + { + Ogre::Entity *ent = mEntityList.mEntities[i]; + + bool transparent = false; + for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + { + Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements() && !transparent) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements() && !transparent) + { + Ogre::Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } + } + } + ent->setVisibilityFlags(RV_Misc); + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + } + } +} + +void ActivatorAnimation::runAnimation(float timepassed) +{ + // Placeholder + + Animation::runAnimation(timepassed); +} + +} diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp new file mode 100644 index 000000000..f3d8d86c8 --- /dev/null +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -0,0 +1,23 @@ +#ifndef _GAME_RENDER_ACTIVATORANIMATION_H +#define _GAME_RENDER_ACTIVATORANIMATION_H + +#include "animation.hpp" + +namespace MWWorld +{ + class Ptr; +} + +namespace MWRender +{ + class ActivatorAnimation : public Animation + { + public: + ActivatorAnimation(const MWWorld::Ptr& ptr); + virtual ~ActivatorAnimation(); + + virtual void runAnimation(float timepassed); + }; +} + +#endif diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 10b654834..d62e16fa2 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,6 +6,7 @@ #include "../mwworld/ptr.hpp" #include "animation.hpp" +#include "activatoranimation.hpp" #include "creatureanimation.hpp" #include "npcanimation.hpp" @@ -78,6 +79,13 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr) delete mAllActors[ptr]; mAllActors[ptr] = anim; } +void Actors::insertActivator (const MWWorld::Ptr& ptr) +{ + insertBegin(ptr); + ActivatorAnimation* anim = new ActivatorAnimation(ptr); + delete mAllActors[ptr]; + mAllActors[ptr] = anim; +} bool Actors::deleteObject (const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 92965a059..4ef78c577 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -31,8 +31,9 @@ namespace MWRender void setMwRoot(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr); - void insertCreature (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); + void insertCreature (const MWWorld::Ptr& ptr); + void insertActivator (const MWWorld::Ptr& ptr); bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5341ffd7a..978419845 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -200,6 +200,9 @@ void Animation::playGroup(std::string groupname, int mode, int loops) GroupTimes times; try { + if(!mEntityList.mSkelBase) + throw std::runtime_error("Attempting to animate an inanimate object"); + std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); times.mLoops = loops; From 3c32385e17f878e72a631d976cf3ae17fb8a6cef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 15:00:06 -0800 Subject: [PATCH 377/916] Avoid trying to animate things that don't have animations --- apps/openmw/mwmechanics/character.cpp | 7 +++++-- apps/openmw/mwrender/animation.cpp | 17 +++++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5bf468ffb..47288b0c1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,7 +29,7 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(!mAnimation) + if(!mAnimation || mAnimation->getAnimationCount() == 0) return; mAnimation->setController(this); @@ -47,7 +47,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) { - if(!mAnimation) + if(!mAnimation || mAnimation->getAnimationCount() == 0) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -68,6 +68,9 @@ void CharacterController::markerEvent(const std::string &evt) void CharacterController::setState(CharacterState state) { mState = state; + + if(!mAnimation || mAnimation->getAnimationCount() == 0) + return; switch(mState) { case CharState_Idle: diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 978419845..66d64f9d4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,6 +98,23 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } +int Animation::getAnimationCount() +{ + int num = 0; + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); + while(ai.hasMoreElements()) + { + num++; + ai.moveNext(); + } + } + return num; +} + + void Animation::setController(MWMechanics::CharacterController *controller) { mController = controller; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 43cce0c02..0e5c7e66e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -66,6 +66,8 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); + int getAnimationCount(); + void playGroup(std::string groupname, int mode, int loops); void skipAnim(); virtual void runAnimation(float timepassed); From 46728ab27ff387b46fd8b0893400218c8af10be2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 15:52:03 -0800 Subject: [PATCH 378/916] Handle "sound:" animation events --- apps/openmw/mwmechanics/character.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 47288b0c1..6acd9a7cf 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,9 @@ #include "../mwrender/animation.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" + #include "../mwworld/class.hpp" namespace MWMechanics @@ -56,11 +59,10 @@ CharacterController::CharacterController(const CharacterController &rhs) void CharacterController::markerEvent(const std::string &evt) { - std::string::size_type gp = evt.find(':'); - if(gp >= evt.length()-2) + if(evt.compare(0, 6, "sound:") == 0) { - std::cerr<< "Unexpected animation marker: \""<playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); } } From 4c0e0fc279e833b5092caf3f7198dc6b50b20c7c Mon Sep 17 00:00:00 2001 From: pvdk Date: Thu, 17 Jan 2013 01:30:15 +0100 Subject: [PATCH 379/916] Modified license filename of the DejaVu font, more similar to the other one now --- Dejavu_lgc_font_license.txt => DejaVu Font License.txt | 0 credits.txt | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Dejavu_lgc_font_license.txt => DejaVu Font License.txt (100%) diff --git a/Dejavu_lgc_font_license.txt b/DejaVu Font License.txt similarity index 100% rename from Dejavu_lgc_font_license.txt rename to DejaVu Font License.txt diff --git a/credits.txt b/credits.txt index 878cbf915..5d486c74e 100644 --- a/credits.txt +++ b/credits.txt @@ -119,4 +119,4 @@ Thanks to Dongle, for his Daedric fontface, see Daedric Font License.txt for his license terms. Thanks to DejaVu team, -for their DejaVuLGCSansMono fontface, see Dejavu_lgc_font_license.txt for their license terms. +for their DejaVuLGCSansMono fontface, see DejaVu Font License.txt for their license terms. From 46fc61a4c19877a883f44d161fd95c31fc023015 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 16:31:09 -0800 Subject: [PATCH 380/916] Run animations from the character controller --- apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/character.cpp | 15 ++++++++++++--- apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/actors.cpp | 3 +-- apps/openmw/mwrender/player.cpp | 3 --- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 23272e674..7205e7d54 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -263,6 +263,7 @@ namespace MWMechanics std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { + iter->second.update(duration); Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6acd9a7cf..87ed8a9e6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -32,7 +32,9 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(mAnimation && mAnimation->getAnimationCount() == 0) + mAnimation = NULL; + if(!mAnimation) return; mAnimation->setController(this); @@ -50,7 +52,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) { - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -67,11 +69,18 @@ void CharacterController::markerEvent(const std::string &evt) } +void CharacterController::update(float duration) +{ + if(mAnimation) + mAnimation->runAnimation(duration); +} + + void CharacterController::setState(CharacterState state) { mState = state; - if(!mAnimation || mAnimation->getAnimationCount() == 0) + if(!mAnimation) return; switch(mState) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c09cb8e42..3a59ae4bb 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -33,6 +33,8 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); CharacterController(const CharacterController &rhs); + void update(float duration); + void setState(CharacterState state); CharacterState getState() const { return mState; } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index d62e16fa2..91395277b 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -149,8 +149,7 @@ void Actors::skipAnimation (const MWWorld::Ptr& ptr) } void Actors::update (float duration) { - for(PtrAnimationMap::const_iterator iter = mAllActors.begin();iter != mAllActors.end();iter++) - iter->second->runAnimation(duration); + // Nothing to do } Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 0e4c76b0e..8f3e13039 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -129,9 +129,6 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - if (mAnimation) { - mAnimation->runAnimation(duration); - } mPlayerNode->setVisible( mVanity.enabled || mPreviewMode || !mFirstPersonView, false From 4feaa66897e55ff9ffc2a011bceed5fee1156799 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 17 Jan 2013 01:58:44 +0100 Subject: [PATCH 381/916] Do not open the dialogue window if no greeting is found --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f9d8c3459..535145a00 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -122,15 +122,9 @@ namespace MWDialogue MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); mTalkedTo = creatureStats.hasTalkedToPlayer(); - creatureStats.talkedToPlayer(); mActorKnownTopics.clear(); - //initialise the GUI - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); - //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI updateTopics(); @@ -146,6 +140,13 @@ namespace MWDialogue { if (const ESM::DialInfo *info = filter.search (*it)) { + //initialise the GUI + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); + + creatureStats.talkedToPlayer(); + if (!info->mSound.empty()) { // TODO play sound From d2f5a886c731fe9d20ce176f81a5b20bb80c5077 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 17:53:18 -0800 Subject: [PATCH 382/916] Handle playgroup and skipanim through mwmechanics --- apps/openmw/mwbase/mechanicsmanager.hpp | 11 +++++++++++ apps/openmw/mwbase/world.hpp | 12 ------------ apps/openmw/mwmechanics/actors.cpp | 13 +++++++++++++ apps/openmw/mwmechanics/actors.hpp | 3 +++ apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++++ apps/openmw/mwmechanics/character.hpp | 3 +++ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 10 ++++++++++ apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 3 +++ apps/openmw/mwrender/actors.cpp | 12 ------------ apps/openmw/mwrender/actors.hpp | 12 ------------ apps/openmw/mwrender/renderingmanager.cpp | 11 ----------- apps/openmw/mwrender/renderingmanager.hpp | 12 ------------ apps/openmw/mwscript/animationextensions.cpp | 8 ++++---- apps/openmw/mwworld/worldimp.cpp | 11 ----------- apps/openmw/mwworld/worldimp.hpp | 12 ------------ 15 files changed, 61 insertions(+), 86 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 401e360d7..f7bbd6a9f 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -95,6 +95,17 @@ namespace MWBase virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; ///< Perform a persuasion action on NPC + + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + ///< Run animation for a MW-reference. Calls to this function for references that are currently not + /// in the scene should be ignored. + /// + /// \param mode 0 normal, 1 immediate start, 2 immediate loop + /// \param count How many times the animation should be run + + virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; + ///< Skip the animation for the given MW-reference for one frame. Calls to this function for + /// references that are currently not in the scene should be ignored. }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f846c51ba..c75e96a6e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -260,18 +260,6 @@ namespace MWBase ///< Create a new recrod (of type npc) in the ESM store. /// \return pointer to created record - virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number = 1) = 0; - ///< Run animation for a MW-reference. Calls to this function for references that are - /// currently not in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - virtual void skipAnimation (const MWWorld::Ptr& ptr) = 0; - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - virtual void update (float duration, bool paused) = 0; virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7205e7d54..749fb2665 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -288,4 +288,17 @@ namespace MWMechanics return iter->second; return 0; } + + void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + iter->second.playGroup(groupName, mode, number); + } + void Actors::skipAnimation(const MWWorld::Ptr& ptr) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + iter->second.skipAnim(); + } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index faf21a12f..6fed9eff7 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -68,6 +68,9 @@ namespace MWMechanics int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); }; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 87ed8a9e6..21697f996 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -76,6 +76,20 @@ void CharacterController::update(float duration) } +void CharacterController::playGroup(const std::string &groupname, int mode, int count) +{ + // set mState = CharState_Idle? + if(mAnimation) + mAnimation->playGroup(groupname, mode, count); +} + +void CharacterController::skipAnim() +{ + if(mAnimation) + mAnimation->skipAnim(); +} + + void CharacterController::setState(CharacterState state) { mState = state; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 3a59ae4bb..24e129e38 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -35,6 +35,9 @@ public: void update(float duration); + void playGroup(const std::string &groupname, int mode, int count); + void skipAnim(); + void setState(CharacterState state); CharacterState getState() const { return mState; } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3b57c3485..84145eb08 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -628,4 +628,14 @@ namespace MWMechanics permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; } } + + void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + { + mActors.playAnimationGroup(ptr, groupName, mode, number); + } + void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) + { + mActors.skipAnimation(ptr); + } + } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 549807285..c2bbd96cf 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -89,6 +89,9 @@ namespace MWMechanics float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); void toLower(std::string npcFaction); ///< Perform a persuasion action on NPC + + virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + virtual void skipAnimation(const MWWorld::Ptr& ptr); }; } diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 91395277b..12ebdab61 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -135,18 +135,6 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) } } -void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) -{ - PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); - if(iter != mAllActors.end()) - iter->second->playGroup(groupName, mode, number); -} -void Actors::skipAnimation (const MWWorld::Ptr& ptr) -{ - PtrAnimationMap::const_iterator iter = mAllActors.find(ptr); - if(iter != mAllActors.end()) - iter->second->skipAnim(); -} void Actors::update (float duration) { // Nothing to do diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 4ef78c577..fc9fa4fbb 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -39,18 +39,6 @@ namespace MWRender void removeCell(MWWorld::CellStore* store); - void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are currently not - /// in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - void update (float duration); /// Updates containing cell for object rendering data diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d1f0b17aa..ea898e1fa 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -580,17 +580,6 @@ void RenderingManager::toggleLight() setAmbientMode(); } -void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number) -{ - mActors.playAnimationGroup(ptr, groupName, mode, number); -} - -void RenderingManager::skipAnimation (const MWWorld::Ptr& ptr) -{ - mActors.skipAnimation(ptr); -} - void RenderingManager::setSunColour(const Ogre::ColourValue& colour) { if (!mSunEnabled) return; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1a7d213f3..b6c33f9c0 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -167,18 +167,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList /// configure fog manually void configureFog(const float density, const Ogre::ColourValue& colour); - void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are currently not - /// in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); ///< transform the specified bounding box (in world coordinates) into screen coordinates. /// @return packed vector4 (min_x, min_y, max_x, max_y) diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 6f9253e5d..fc52e5e16 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -9,7 +9,7 @@ #include #include -#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -27,7 +27,7 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - MWBase::Environment::get().getWorld()->skipAnimation (ptr); + MWBase::Environment::get().getMechanicsManager()->skipAnimation (ptr); } }; @@ -54,7 +54,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, 1); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, 1); } }; @@ -87,7 +87,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getWorld()->playAnimationGroup (ptr, group, mode, loops); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, loops); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b855bab8f..de4cb84ef 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -903,17 +903,6 @@ namespace MWWorld return ret; } - void World::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number) - { - mRendering->playAnimationGroup (ptr, groupName, mode, number); - } - - void World::skipAnimation (const MWWorld::Ptr& ptr) - { - mRendering->skipAnimation (ptr); - } - void World::update (float duration, bool paused) { mWorldScene->update (duration, paused); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index f622144b2..67185833f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -291,18 +291,6 @@ namespace MWWorld /// \return pointer to created record - virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, - int mode, int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are - /// currently not in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - virtual void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - virtual void update (float duration, bool paused); virtual bool placeObject (const Ptr& object, float cursorX, float cursorY); From daad8d985963786242782bd72c7527aa02059006 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 18:03:39 -0800 Subject: [PATCH 383/916] Don't update the character controller while paused --- apps/openmw/mwmechanics/actors.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 749fb2665..101a0a51d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -260,16 +260,18 @@ namespace MWMechanics } } - std::vector > movement; - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + if(!paused) { - iter->second.update(duration); - Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - if(vector!=Ogre::Vector3::ZERO) - movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); - } - if (!paused) + std::vector > movement; + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + iter->second.update(duration); + Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + if(vector!=Ogre::Vector3::ZERO) + movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); + } MWBase::Environment::get().getWorld()->doPhysics (movement, duration); + } } void Actors::restoreDynamicStats() From 685f21956001e5eeb64b5b200748ec89f6e195af Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 18:56:13 -0800 Subject: [PATCH 384/916] Return a movement vector from the character controller update --- apps/openmw/mwmechanics/actors.cpp | 3 +-- apps/openmw/mwmechanics/character.cpp | 3 ++- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 101a0a51d..35bca441a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -265,8 +265,7 @@ namespace MWMechanics std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - iter->second.update(duration); - Ogre::Vector3 vector = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + Ogre::Vector3 vector = iter->second.update(duration); if(vector!=Ogre::Vector3::ZERO) movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 21697f996..8e5ac0a4a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -69,10 +69,11 @@ void CharacterController::markerEvent(const std::string &evt) } -void CharacterController::update(float duration) +Ogre::Vector3 CharacterController::update(float duration) { if(mAnimation) mAnimation->runAnimation(duration); + return MWWorld::Class::get(mPtr).getMovementVector(mPtr); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 24e129e38..83f42887d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -33,7 +33,7 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); CharacterController(const CharacterController &rhs); - void update(float duration); + Ogre::Vector3 update(float duration); void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); From 4dd01b81c6cd63aa0153f2a6efb742e3b0c06a56 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 20:14:49 -0800 Subject: [PATCH 385/916] Update mTime when updating or reseting the animation, and refactor the animation loop --- apps/openmw/mwrender/animation.cpp | 90 +++++++++++++----------------- 1 file changed, 38 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 66d64f9d4..30532b624 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -124,6 +124,8 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + mTime = time; + if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the @@ -150,9 +152,10 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mCurGroup.mAnimState->setTimePosition(time); + mTime = time; mCurGroup.mNext = mCurGroup.mStart; - while(mCurGroup.mNext->first < time) + while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first < time) mCurGroup.mNext++; if(mNonAccumRoot) @@ -233,7 +236,7 @@ void Animation::playGroup(std::string groupname, int mode, int loops) } times.mNext = ((mode==2) ? times.mLoopStart : times.mStart); - if(mode == 0 && mCurGroup.mLoops > 0) + if(mode == 0 && mCurGroup.mAnimState) mNextGroup = times; else { @@ -241,9 +244,8 @@ void Animation::playGroup(std::string groupname, int mode, int loops) mCurGroup.mAnimState->setEnabled(false); mCurGroup = times; mNextGroup = GroupTimes(); - mTime = mCurGroup.mNext->first; mCurGroup.mAnimState->setEnabled(true); - resetPosition(mTime); + resetPosition(mCurGroup.mNext->first); } } @@ -254,62 +256,46 @@ void Animation::skipAnim() void Animation::runAnimation(float timepassed) { - if(mCurGroup.mAnimState && !mSkipFrame) - { - mTime += timepassed; - recheck: - if(mTime >= mCurGroup.mLoopStop->first) - { - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mCurGroup.mLoopStop->first) - { - if(mController) - mController->markerEvent(mCurGroup.mNext->second); - mCurGroup.mNext++; - } + if(mSkipFrame) + timepassed = 0.0f; + mSkipFrame = false; - if(mCurGroup.mLoops > 1) - { - mCurGroup.mLoops--; - updatePosition(mCurGroup.mLoopStop->first); - mTime = mTime - mCurGroup.mLoopStop->first + mCurGroup.mLoopStart->first; - resetPosition(mCurGroup.mLoopStart->first); - goto recheck; - } - else if(mTime >= mCurGroup.mStop->first) - { - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mCurGroup.mStop->first) - { - if(mController) - mController->markerEvent(mCurGroup.mNext->second); - mCurGroup.mNext++; - } - if(mNextGroup.mLoops > 0) - { - updatePosition(mCurGroup.mStop->first); - mTime = mTime - mCurGroup.mStop->first + mNextGroup.mStart->first; - mCurGroup.mAnimState->setEnabled(false); - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mStart->first); - goto recheck; - } - mTime = mCurGroup.mStop->first; - } - } - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= mTime) + while(mCurGroup.mAnimState && timepassed > 0.0f) + { + float targetTime = mTime + timepassed; + if(mCurGroup.mNext != mCurGroup.mTextKeys->end() && + mCurGroup.mNext->first <= targetTime) { + updatePosition(mCurGroup.mNext->first); + timepassed = targetTime - mTime; + if(mController) mController->markerEvent(mCurGroup.mNext->second); + if(mCurGroup.mNext == mCurGroup.mLoopStop && mCurGroup.mLoops > 1) + { + mCurGroup.mLoops--; + resetPosition(mCurGroup.mLoopStart->first); + continue; + } + else if(mCurGroup.mNext == mCurGroup.mStop) + { + if(!mNextGroup.mAnimState) + break; + + mCurGroup.mAnimState->setEnabled(false); + mCurGroup = mNextGroup; + mNextGroup = GroupTimes(); + mCurGroup.mAnimState->setEnabled(true); + resetPosition(mCurGroup.mStart->first); + continue; + } mCurGroup.mNext++; + continue; } - updatePosition(mTime); + updatePosition(targetTime); + timepassed = targetTime - mTime; } - mSkipFrame = false; } } From afbc9f3e41cad0dcc1c29e8ecc36af7facc27c4a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 20:44:37 -0800 Subject: [PATCH 386/916] Keep track of the animation group currently playing --- apps/openmw/mwmechanics/character.cpp | 12 ++++++++---- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8e5ac0a4a..8786c42e1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,10 +41,12 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim switch(mState) { case CharState_Idle: - mAnimation->playGroup("idle", 1, 1); + mCurrentGroup = "idle"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; case CharState_Dead: - mAnimation->playGroup("death1", 1, 1); + mCurrentGroup = "death1"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; } } @@ -100,10 +102,12 @@ void CharacterController::setState(CharacterState state) switch(mState) { case CharState_Idle: - mAnimation->playGroup("idle", 1, 1); + mCurrentGroup = "idle"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; case CharState_Dead: - mAnimation->playGroup("death1", 1, 1); + mCurrentGroup = "death1"; + mAnimation->playGroup(mCurrentGroup, 1, 1); break; } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 83f42887d..9070cbe29 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,6 +21,7 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; + std::string mCurrentGroup; CharacterState mState; protected: From 852aa214cc6562c6f259277fa350f99be8167906 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:16:22 -0800 Subject: [PATCH 387/916] Store the available animation names in the character controller --- apps/openmw/mwmechanics/character.cpp | 16 ++++++++++------ apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwrender/animation.cpp | 11 ++++------- apps/openmw/mwrender/animation.hpp | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8786c42e1..c347312c2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -32,10 +32,13 @@ namespace MWMechanics CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) : mPtr(ptr), mAnimation(anim), mState(state) { - if(mAnimation && mAnimation->getAnimationCount() == 0) + if(mAnimation) + mAnimNames = mAnimation->getAnimationNames(); + if(mAnimNames.size() == 0) + { mAnimation = NULL; - if(!mAnimation) return; + } mAnimation->setController(this); switch(mState) @@ -52,9 +55,10 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mState(rhs.mState) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) + , mState(rhs.mState) { - if(!mAnimation) + if(mAnimNames.size() == 0) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -82,7 +86,7 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { // set mState = CharState_Idle? - if(mAnimation) + if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) mAnimation->playGroup(groupname, mode, count); } @@ -97,7 +101,7 @@ void CharacterController::setState(CharacterState state) { mState = state; - if(!mAnimation) + if(mAnimNames.size() == 0) return; switch(mState) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9070cbe29..c29c39acd 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,6 +21,8 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; + std::vector mAnimNames; + std::string mCurrentGroup; CharacterState mState; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30532b624..1d628aefa 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,20 +98,17 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } -int Animation::getAnimationCount() +std::vector Animation::getAnimationNames() { - int num = 0; + std::vector anims; if(mEntityList.mSkelBase) { Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); while(ai.hasMoreElements()) - { - num++; - ai.moveNext(); - } + anims.push_back(ai.getNext()->getAnimationName()); } - return num; + return anims; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 0e5c7e66e..3afe32a4b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -66,7 +66,7 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); - int getAnimationCount(); + std::vector getAnimationNames(); void playGroup(std::string groupname, int mode, int loops); void skipAnim(); From 7ee389f3b2006bb05aee871e5774c32d64a65b6f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:25:50 -0800 Subject: [PATCH 388/916] Handle animation skipping in the character controller --- apps/openmw/mwmechanics/character.cpp | 10 +++++----- apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwrender/animation.cpp | 10 ---------- apps/openmw/mwrender/animation.hpp | 3 --- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c347312c2..547d9e0a5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,7 +30,7 @@ namespace MWMechanics { CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state) + : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -56,7 +56,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mState(rhs.mState) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -77,8 +77,9 @@ void CharacterController::markerEvent(const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { - if(mAnimation) + if(mAnimation && !mSkipAnim) mAnimation->runAnimation(duration); + mSkipAnim = false; return MWWorld::Class::get(mPtr).getMovementVector(mPtr); } @@ -92,8 +93,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int void CharacterController::skipAnim() { - if(mAnimation) - mAnimation->skipAnim(); + mSkipAnim = true; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c29c39acd..202e10578 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -25,6 +25,7 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; + bool mSkipAnim; protected: /* Called by the animation whenever a new text key is reached. */ diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1d628aefa..c0b6a6e1c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -24,7 +24,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mTime(0.0f) - , mSkipFrame(false) { } @@ -246,17 +245,8 @@ void Animation::playGroup(std::string groupname, int mode, int loops) } } -void Animation::skipAnim() -{ - mSkipFrame = true; -} - void Animation::runAnimation(float timepassed) { - if(mSkipFrame) - timepassed = 0.0f; - mSkipFrame = false; - while(mCurGroup.mAnimState && timepassed > 0.0f) { float targetTime = mTime + timepassed; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3afe32a4b..5dbe7b510 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -48,8 +48,6 @@ protected: GroupTimes mCurGroup; GroupTimes mNextGroup; - bool mSkipFrame; - /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ void updatePosition(float time); @@ -69,7 +67,6 @@ public: std::vector getAnimationNames(); void playGroup(std::string groupname, int mode, int loops); - void skipAnim(); virtual void runAnimation(float timepassed); }; From 82d549e22fc1e97794c31892172263fedc792c69 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 16 Jan 2013 21:39:14 -0800 Subject: [PATCH 389/916] Don't update the animation if time is the same --- apps/openmw/mwrender/animation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0b6a6e1c..d10accab7 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -119,6 +119,8 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { + if(time == mTime) + return; mCurGroup.mAnimState->setTimePosition(time); mTime = time; From da4f17859e12016cf62371ae87730c7f32b20e50 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 10:16:36 -0800 Subject: [PATCH 390/916] Recognize soundgen animation markers --- apps/openmw/mwmechanics/character.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 547d9e0a5..7e5f15a9f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -67,10 +67,17 @@ CharacterController::CharacterController(const CharacterController &rhs) void CharacterController::markerEvent(const std::string &evt) { - if(evt.compare(0, 6, "sound:") == 0) + if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + return; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + return; } } From 47c157303ac64e2fc1df34b1f87a4fe3fff28192 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 11:03:58 -0800 Subject: [PATCH 391/916] Filter events that do not belong to the current group --- apps/openmw/mwmechanics/character.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7e5f15a9f..4385d0b9d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -56,7 +56,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -79,6 +79,12 @@ void CharacterController::markerEvent(const std::string &evt) // to this actor type return; } + if(evt.length() <= mCurrentGroup.length()+2 || evt.compare(0, mCurrentGroup.length(), mCurrentGroup) != 0 || + evt.compare(mCurrentGroup.length(), 2, ": ") != 0) + { + std::cerr<< "Event \""< Date: Thu, 17 Jan 2013 13:18:40 -0800 Subject: [PATCH 392/916] Handle the animation queue in mwmechanics --- apps/openmw/mwmechanics/character.cpp | 55 ++++++++-- apps/openmw/mwmechanics/character.hpp | 3 + apps/openmw/mwrender/animation.cpp | 123 ++++++---------------- apps/openmw/mwrender/animation.hpp | 26 +---- apps/openmw/mwrender/characterpreview.cpp | 2 +- 5 files changed, 91 insertions(+), 118 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4385d0b9d..9fa2c74be 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -45,18 +45,19 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim { case CharState_Idle: mCurrentGroup = "idle"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "stop"); break; } } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; @@ -79,12 +80,33 @@ void CharacterController::markerEvent(const std::string &evt) // to this actor type return; } - if(evt.length() <= mCurrentGroup.length()+2 || evt.compare(0, mCurrentGroup.length(), mCurrentGroup) != 0 || - evt.compare(mCurrentGroup.length(), 2, ": ") != 0) + std::string::size_type ms = mCurrentGroup.length()+2; + if(evt.length() <= ms || evt.compare(0, ms-2, mCurrentGroup) != 0 || evt.compare(ms-2, 2, ": ") != 0) { std::cerr<< "Event \""<= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start"); + } + } + else if(mAnimQueue.size() > 0) + { + if(evt.compare(ms, evt.length()-ms, "stop") == 0) + { + mAnimQueue.pop_front(); + if(mAnimQueue.size() > 0) + { + mCurrentGroup = mAnimQueue.front(); + mAnimation->play(mCurrentGroup, "start"); + } + } + } } @@ -101,7 +123,23 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int { // set mState = CharState_Idle? if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) - mAnimation->playGroup(groupname, mode, count); + { + count = std::max(count, 1); + if(mode != 0 || mAnimQueue.size() == 0) + { + mAnimQueue.clear(); + while(count-- > 0) + mAnimQueue.push_back(groupname); + mCurrentGroup = groupname; + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); + } + else if(mode == 0) + { + mAnimQueue.resize(1); + while(count-- > 0) + mAnimQueue.push_back(groupname); + } + } } void CharacterController::skipAnim() @@ -116,15 +154,16 @@ void CharacterController::setState(CharacterState state) if(mAnimNames.size() == 0) return; + mAnimQueue.clear(); switch(mState) { case CharState_Idle: mCurrentGroup = "idle"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; - mAnimation->playGroup(mCurrentGroup, 1, 1); + mAnimation->play(mCurrentGroup, "start"); break; } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 202e10578..992cb8f1f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -23,6 +23,9 @@ class CharacterController std::vector mAnimNames; + typedef std::deque AnimationQueue; + AnimationQueue mAnimQueue; + std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d10accab7..4d9ee108c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,6 +23,8 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mStartPosition(0.0f) , mLastPosition(0.0f) + , mCurrentKeys(NULL) + , mAnimState(NULL) , mTime(0.0f) { } @@ -121,14 +123,14 @@ void Animation::updatePosition(float time) { if(time == mTime) return; - mCurGroup.mAnimState->setTimePosition(time); + mAnimState->setTimePosition(time); mTime = time; if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; /* Translate the accumulation root back to compensate for the move. */ @@ -149,136 +151,81 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { - mCurGroup.mAnimState->setTimePosition(time); + mAnimState->setTimePosition(time); mTime = time; - mCurGroup.mNext = mCurGroup.mStart; - while(mCurGroup.mNext != mCurGroup.mTextKeys->end() && mCurGroup.mNext->first < time) - mCurGroup.mNext++; + mNextKey = mCurrentKeys->begin(); + while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) + mNextKey++; if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mCurGroup.mAnimState->getParent()); + mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } } -bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) +float Animation::findStart(const std::string &groupname, const std::string &start) { - times->mTextKeys = &mTextKeys[groupname]; - const NifOgre::TextKeyMap &textkeys = *times->mTextKeys; - if(textkeys.size() == 0) - return false; + mNextKey = mCurrentKeys->end(); + if(mCurrentKeys->size() == 0) + return 0.0f; if(groupname == "all") { - times->mStart = times->mLoopStart = textkeys.begin(); - times->mLoopStop = times->mStop = textkeys.end(); - times->mLoopStop--; times->mStop--; - return true; + mNextKey = mCurrentKeys->begin(); + return 0.0f; } - const std::string start = groupname+": start"; - const std::string startloop = groupname+": loop start"; - const std::string stop = groupname+": stop"; - const std::string stoploop = groupname+": loop stop"; - - times->mStart = times->mLoopStart = - times->mStop = times->mLoopStop = textkeys.end(); - + std::string startmarker = groupname+": "+start; NifOgre::TextKeyMap::const_iterator iter; - for(iter = textkeys.begin();iter != textkeys.end();iter++) + for(iter = mCurrentKeys->begin();iter != mCurrentKeys->end();iter++) { - if(start == iter->second) - { - times->mStart = iter; - times->mLoopStart = iter; - } - else if(startloop == iter->second) - times->mLoopStart = iter; - else if(stoploop == iter->second) - times->mLoopStop = iter; - else if(stop == iter->second) - { - times->mStop = iter; - if(times->mLoopStop == textkeys.end()) - times->mLoopStop = iter; - return (times->mStart != textkeys.end()); - } + if(iter->second == startmarker) + return iter->first; } - - return false; + return 0.0f; } -void Animation::playGroup(std::string groupname, int mode, int loops) +void Animation::play(const std::string &groupname, const std::string &start) { - GroupTimes times; - + float time = 0.0f; try { if(!mEntityList.mSkelBase) throw std::runtime_error("Attempting to animate an inanimate object"); - std::transform(groupname.begin(), groupname.end(), groupname.begin(), ::tolower); - times.mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - times.mLoops = loops; + if(mAnimState) + mAnimState->setEnabled(false); + mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); + mCurrentKeys = &mTextKeys[groupname]; + mAnimState->setEnabled(true); - if(!findGroupTimes(groupname, ×)) - throw std::runtime_error("Failed to find animation group "+groupname); + time = findStart(groupname, start); } catch(std::exception &e) { std::cerr<< e.what() <setEnabled(false); - mCurGroup = times; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mNext->first); - } + resetPosition(time); } void Animation::runAnimation(float timepassed) { - while(mCurGroup.mAnimState && timepassed > 0.0f) + while(mAnimState && timepassed > 0.0f) { float targetTime = mTime + timepassed; - if(mCurGroup.mNext != mCurGroup.mTextKeys->end() && - mCurGroup.mNext->first <= targetTime) + if(mNextKey != mCurrentKeys->end() && mNextKey->first <= targetTime) { - updatePosition(mCurGroup.mNext->first); + const std::string &evt = mNextKey->second; + updatePosition(mNextKey->first); + mNextKey++; timepassed = targetTime - mTime; if(mController) - mController->markerEvent(mCurGroup.mNext->second); - if(mCurGroup.mNext == mCurGroup.mLoopStop && mCurGroup.mLoops > 1) - { - mCurGroup.mLoops--; - resetPosition(mCurGroup.mLoopStart->first); - continue; - } - else if(mCurGroup.mNext == mCurGroup.mStop) - { - if(!mNextGroup.mAnimState) - break; - - mCurGroup.mAnimState->setEnabled(false); - mCurGroup = mNextGroup; - mNextGroup = GroupTimes(); - mCurGroup.mAnimState->setEnabled(true); - resetPosition(mCurGroup.mStart->first); - continue; - } - mCurGroup.mNext++; + mController->markerEvent(evt); continue; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5dbe7b510..722eccc30 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -15,23 +15,6 @@ namespace MWRender class Animation { - struct GroupTimes { - NifOgre::TextKeyMap *mTextKeys; - - NifOgre::TextKeyMap::const_iterator mStart; - NifOgre::TextKeyMap::const_iterator mStop; - NifOgre::TextKeyMap::const_iterator mLoopStart; - NifOgre::TextKeyMap::const_iterator mLoopStop; - - NifOgre::TextKeyMap::const_iterator mNext; - - Ogre::AnimationState *mAnimState; - size_t mLoops; - - GroupTimes() : mTextKeys(NULL), mAnimState(NULL), mLoops(0) - { } - }; - protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; @@ -44,9 +27,10 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + NifOgre::TextKeyMap *mCurrentKeys; + NifOgre::TextKeyMap::const_iterator mNextKey; + Ogre::AnimationState *mAnimState; float mTime; - GroupTimes mCurGroup; - GroupTimes mNextGroup; /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ @@ -55,7 +39,7 @@ protected: * object. */ void resetPosition(float time); - bool findGroupTimes(const std::string &groupname, GroupTimes *times); + float findStart(const std::string &groupname, const std::string &start); void createEntityList(Ogre::SceneNode *node, const std::string &model); @@ -66,7 +50,7 @@ public: void setController(MWMechanics::CharacterController *controller); std::vector getAnimationNames(); - void playGroup(std::string groupname, int mode, int loops); + void play(const std::string &groupname, const std::string &start); virtual void runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index eb9954df6..cbee9c865 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -144,7 +144,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->playGroup ("inventoryhandtohand", 0, 1); + mAnimation->play("inventoryhandtohand", "start"); } // -------------------------------------------------------------------------------------------------- From fc0f9e215909e15b5a09eb7edafdda4ce9dceada Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 14:49:42 -0800 Subject: [PATCH 393/916] The animation state tracks the animation time for us --- apps/openmw/mwrender/animation.cpp | 28 +++++++++++----------------- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4d9ee108c..18aa98215 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -25,7 +25,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) - , mTime(0.0f) { } @@ -121,10 +120,7 @@ void Animation::setController(MWMechanics::CharacterController *controller) void Animation::updatePosition(float time) { - if(time == mTime) - return; mAnimState->setTimePosition(time); - mTime = time; if(mNonAccumRoot) { @@ -152,7 +148,6 @@ void Animation::updatePosition(float time) void Animation::resetPosition(float time) { mAnimState->setTimePosition(time); - mTime = time; mNextKey = mCurrentKeys->begin(); while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) @@ -216,21 +211,20 @@ void Animation::runAnimation(float timepassed) { while(mAnimState && timepassed > 0.0f) { - float targetTime = mTime + timepassed; - if(mNextKey != mCurrentKeys->end() && mNextKey->first <= targetTime) + float targetTime = mAnimState->getTimePosition() + timepassed; + if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - const std::string &evt = mNextKey->second; - updatePosition(mNextKey->first); - mNextKey++; - timepassed = targetTime - mTime; - - if(mController) - mController->markerEvent(evt); - continue; + updatePosition(targetTime); + break; } - updatePosition(targetTime); - timepassed = targetTime - mTime; + const std::string &evt = mNextKey->second; + updatePosition(mNextKey->first); + timepassed = targetTime - mNextKey->first; + mNextKey++; + + if(mController) + mController->markerEvent(evt); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 722eccc30..726d0cf38 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -30,7 +30,6 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; - float mTime; /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ From fef6284f15ebf7cafcfed1e3bb7e4a3727cddafe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 15:47:25 -0800 Subject: [PATCH 394/916] Only reset the animation time if a new state was set --- apps/openmw/mwrender/animation.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 18aa98215..1a464f5d8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -187,24 +187,22 @@ float Animation::findStart(const std::string &groupname, const std::string &star void Animation::play(const std::string &groupname, const std::string &start) { - float time = 0.0f; try { if(!mEntityList.mSkelBase) throw std::runtime_error("Attempting to animate an inanimate object"); + Ogre::AnimationState *newstate = mEntityList.mSkelBase->getAnimationState(groupname); if(mAnimState) mAnimState->setEnabled(false); - mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mCurrentKeys = &mTextKeys[groupname]; + mAnimState = newstate; mAnimState->setEnabled(true); + mCurrentKeys = &mTextKeys[groupname]; - time = findStart(groupname, start); + resetPosition(findStart(groupname, start)); } catch(std::exception &e) { std::cerr<< e.what() < Date: Thu, 17 Jan 2013 15:48:09 -0800 Subject: [PATCH 395/916] Fix player rendering --- apps/openmw/mwrender/player.hpp | 4 +++- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 29a68ca69..e24f44d68 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -95,7 +95,9 @@ namespace MWRender /// Restore default camera distance for current mode. void setCameraDistance(); - void setAnimation(MWRender::NpcAnimation *anim); + void setAnimation(NpcAnimation *anim); + NpcAnimation *getAnimation() const + { return mAnimation; } void setHeight(float height); float getHeight(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ea898e1fa..082b561ef 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -921,7 +921,7 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors.getAnimation(ptr); - // TODO: Check mObjects too. + if(!anim) anim = mPlayer->getAnimation(); return anim; } From 8fa1b56efcbfc9869c9b22d14f0c1bfb72853de4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 16:34:26 -0800 Subject: [PATCH 396/916] Loop the current animation if there's nothing more queued --- apps/openmw/mwmechanics/character.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9fa2c74be..a42771e0b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -107,6 +107,11 @@ void CharacterController::markerEvent(const std::string &evt) } } } + else + { + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + mAnimation->play(mCurrentGroup, "loop start"); + } } @@ -130,6 +135,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); while(count-- > 0) mAnimQueue.push_back(groupname); + mAnimQueue.push_back("idle"); mCurrentGroup = groupname; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -138,6 +144,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.resize(1); while(count-- > 0) mAnimQueue.push_back(groupname); + mAnimQueue.push_back("idle"); } } } From 8720433fa9e171c1776db6845f93ad4c4986256b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 17:38:05 -0800 Subject: [PATCH 397/916] Do not automatically loop animations There are 0 length idle animations that break this --- apps/openmw/mwmechanics/character.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a42771e0b..0b8eff733 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -107,11 +107,6 @@ void CharacterController::markerEvent(const std::string &evt) } } } - else - { - if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) - mAnimation->play(mCurrentGroup, "loop start"); - } } From 9d7ccfda1ffa7edd79b52cc777466c55181296a8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 17 Jan 2013 21:07:36 -0800 Subject: [PATCH 398/916] Rename CharState_Idle to CharState_Alive --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 5 ++--- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35bca441a..00350fcc2 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Alive))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); } @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Idle); + iter->second.setState(CharState_Alive); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0b8eff733..4e861f35c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,7 +43,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); switch(mState) { - case CharState_Idle: + case CharState_Alive: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; @@ -121,7 +121,6 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - // set mState = CharState_Idle? if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) { count = std::max(count, 1); @@ -159,7 +158,7 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { - case CharState_Idle: + case CharState_Alive: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 992cb8f1f..cdbe439a4 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,7 +12,7 @@ namespace MWMechanics { enum CharacterState { - CharState_Idle, + CharState_Alive, CharState_Dead }; From a94947029e41e0337c5163dc1d1fd7d1496fde1d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 00:59:48 -0800 Subject: [PATCH 399/916] Check the marker name before deciding what to do with it Also, don't force 'idle' after a playgroup --- apps/openmw/mwmechanics/character.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4e861f35c..0767df130 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -87,17 +87,24 @@ void CharacterController::markerEvent(const std::string &evt) return; } - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(evt.compare(ms, evt.length()-ms, "loop stop") == 0) { - if(evt.compare(ms, evt.length()-ms, "loop stop") == 0 || evt.compare(ms, evt.length()-ms, "stop") == 0) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); } + return; } - else if(mAnimQueue.size() > 0) + + if(evt.compare(ms, evt.length()-ms, "stop") == 0) { - if(evt.compare(ms, evt.length()-ms, "stop") == 0) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() > 0) { mAnimQueue.pop_front(); if(mAnimQueue.size() > 0) @@ -106,6 +113,7 @@ void CharacterController::markerEvent(const std::string &evt) mAnimation->play(mCurrentGroup, "start"); } } + return; } } @@ -129,7 +137,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); while(count-- > 0) mAnimQueue.push_back(groupname); - mAnimQueue.push_back("idle"); mCurrentGroup = groupname; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -138,7 +145,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.resize(1); while(count-- > 0) mAnimQueue.push_back(groupname); - mAnimQueue.push_back("idle"); } } } From 5cafc24ee2b619898afdda0914e4da6b79f77464 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 13:43:45 -0800 Subject: [PATCH 400/916] Rename CharState_Alive back to CharState_Idle --- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 00350fcc2..35bca441a 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Alive))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); } @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Alive); + iter->second.setState(CharState_Idle); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 0767df130..96221cbb8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -43,7 +43,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); switch(mState) { - case CharState_Alive: + case CharState_Idle: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; @@ -164,7 +164,7 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { - case CharState_Alive: + case CharState_Idle: mCurrentGroup = "idle"; mAnimation->play(mCurrentGroup, "start"); break; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index cdbe439a4..992cb8f1f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,7 +12,7 @@ namespace MWMechanics { enum CharacterState { - CharState_Alive, + CharState_Idle, CharState_Dead }; From 3e9b0a333cea79ba76b684bdb83b086c89028432 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 14:25:32 -0800 Subject: [PATCH 401/916] Allow specifying the accumulation for animations Animations that move a character may do so either visually or physically. An axis' accumuluation value specifies whether the movement is visual (0) or physical (1). Idle animations, for instance, typically don't physically move a character, while death animations may physically move them along the X and Y planes, but not along Z (the vertical movement is purely visual). --- apps/openmw/mwmechanics/character.cpp | 15 ++++----------- apps/openmw/mwrender/animation.cpp | 9 ++++++++- apps/openmw/mwrender/animation.hpp | 6 ++++++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 96221cbb8..f5b6301a2 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,17 +41,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - switch(mState) - { - case CharState_Idle: - mCurrentGroup = "idle"; - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_Dead: - mCurrentGroup = "death1"; - mAnimation->play(mCurrentGroup, "stop"); - break; - } + setState(mState); } CharacterController::CharacterController(const CharacterController &rhs) @@ -138,6 +128,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; + mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } else if(mode == 0) @@ -166,10 +157,12 @@ void CharacterController::setState(CharacterState state) { case CharState_Idle: mCurrentGroup = "idle"; + mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, "start"); break; case CharState_Dead: mCurrentGroup = "death1"; + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); mAnimation->play(mCurrentGroup, "start"); break; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1a464f5d8..b6c712522 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -21,6 +21,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mInsert(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mAccumulate(Ogre::Vector3::ZERO) , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) @@ -118,6 +119,12 @@ void Animation::setController(MWMechanics::CharacterController *controller) } +void Animation::setAccumulation(const Ogre::Vector3 &accum) +{ + mAccumulate = accum; +} + + void Animation::updatePosition(float time) { mAnimState->setTimePosition(time); @@ -127,7 +134,7 @@ void Animation::updatePosition(float time) /* Update the animation and get the non-accumulation root's difference from the * last update. */ mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); - Ogre::Vector3 posdiff = mNonAccumRoot->getPosition() - mLastPosition; + Ogre::Vector3 posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 726d0cf38..32d51775a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -24,6 +24,7 @@ protected: std::map mTextKeys; Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; @@ -49,6 +50,11 @@ public: void setController(MWMechanics::CharacterController *controller); std::vector getAnimationNames(); + // Specifies the axis' to accumulate on. Non-accumulated axis will just + // move visually, but not affect the actual movement. Each x/y/z value + // should be on the scale of 0 to 1. + void setAccumulation(const Ogre::Vector3 &accum); + void play(const std::string &groupname, const std::string &start); virtual void runAnimation(float timepassed); }; From c7684cb979bc0c4791d6e88bb9cf626764ed3417 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 14:50:55 -0800 Subject: [PATCH 402/916] Pass the key time to markerEvent --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f5b6301a2..241033802 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -56,7 +56,7 @@ CharacterController::CharacterController(const CharacterController &rhs) } -void CharacterController::markerEvent(const std::string &evt) +void CharacterController::markerEvent(float time, const std::string &evt) { if(evt.compare(0, 7, "sound: ") == 0) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 992cb8f1f..902b8cc36 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -32,7 +32,7 @@ class CharacterController protected: /* Called by the animation whenever a new text key is reached. */ - void markerEvent(const std::string &evt); + void markerEvent(float time, const std::string &evt); friend class MWRender::Animation; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b6c712522..cfc72de37 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -223,13 +223,15 @@ void Animation::runAnimation(float timepassed) break; } + float time = mNextKey->first; const std::string &evt = mNextKey->second; - updatePosition(mNextKey->first); - timepassed = targetTime - mNextKey->first; mNextKey++; + updatePosition(time); + timepassed = targetTime - time; + if(mController) - mController->markerEvent(evt); + mController->markerEvent(time, evt); } } From a527cb8349fd1b4e6b0fa12ac70ab83bb78d4449 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 15:22:14 -0800 Subject: [PATCH 403/916] Loop the current animation when not dead This should be better, but it's not perfect. It misses the case where start < loop start == loop stop <= stop --- apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 241033802..97cdf3f49 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -79,7 +79,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(evt.compare(ms, evt.length()-ms, "loop stop") == 0) { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() == 0) + { + if(time > 0.0f && mState != CharState_Dead) + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); @@ -89,7 +94,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(evt.compare(ms, evt.length()-ms, "stop") == 0) { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() == 0) + { + if(time > 0.0f && mState != CharState_Dead) + mAnimation->play(mCurrentGroup, "loop start"); + } + else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); mAnimation->play(mCurrentGroup, "loop start"); From 40f8e757637927d631ff97aa4a14d0b7c911bddf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 15:39:28 -0800 Subject: [PATCH 404/916] Use a SpecialIdle state for PlayGroup/LoopGroup invoked animations Note that actors will *not* automatically resume a normal idle state afterward. Their AI will need to control what to do when the special idle is finished. --- apps/openmw/mwmechanics/character.cpp | 3 +++ apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 97cdf3f49..73a6f2c9c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -138,6 +138,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; + mState = CharState_SpecialIdle; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -165,6 +166,8 @@ void CharacterController::setState(CharacterState state) mAnimQueue.clear(); switch(mState) { + case CharState_SpecialIdle: + break; case CharState_Idle: mCurrentGroup = "idle"; mAnimation->setAccumulation(Ogre::Vector3::ZERO); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 902b8cc36..47bb27e83 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -12,6 +12,7 @@ namespace MWMechanics { enum CharacterState { + CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, CharState_Dead }; From 9235fba77058e5ade49e5b64f988694ecfde2c2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 16:00:51 -0800 Subject: [PATCH 405/916] Store the movement vector in the character controller --- apps/openmw/mwmechanics/actors.cpp | 6 ++++++ apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 35bca441a..396f34eab 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -262,6 +262,12 @@ namespace MWMechanics if(!paused) { + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) + { + Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + iter->second.setDirection(dir); + } + std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 73a6f2c9c..ff400b9d1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ Ogre::Vector3 CharacterController::update(float duration) if(mAnimation && !mSkipAnim) mAnimation->runAnimation(duration); mSkipAnim = false; - return MWWorld::Class::get(mPtr).getMovementVector(mPtr); + return mDirection; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 47bb27e83..c151b3b9f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWMECHANICS_CHARACTER_HPP #define GAME_MWMECHANICS_CHARACTER_HPP +#include + #include "../mwworld/ptr.hpp" namespace MWRender @@ -27,6 +29,8 @@ class CharacterController typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; + Ogre::Vector3 mDirection; + std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; @@ -46,6 +50,9 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); + void setDirection(const Ogre::Vector3 &dir) + { mDirection = dir; } + void setState(CharacterState state); CharacterState getState() const { return mState; } From 9123f4f2afdc7738087dadf59ee5ddee342ea9e8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 16:21:29 -0800 Subject: [PATCH 406/916] Return the movement vector from runAnimation --- apps/openmw/mwrender/activatoranimation.cpp | 7 ------- apps/openmw/mwrender/activatoranimation.hpp | 2 -- apps/openmw/mwrender/animation.cpp | 14 +++++++++----- apps/openmw/mwrender/animation.hpp | 4 ++-- apps/openmw/mwrender/creatureanimation.cpp | 12 ++---------- apps/openmw/mwrender/creatureanimation.hpp | 2 -- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.hpp | 2 +- 8 files changed, 16 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 18ae31865..f951307b6 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -54,11 +54,4 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) } } -void ActivatorAnimation::runAnimation(float timepassed) -{ - // Placeholder - - Animation::runAnimation(timepassed); -} - } diff --git a/apps/openmw/mwrender/activatoranimation.hpp b/apps/openmw/mwrender/activatoranimation.hpp index f3d8d86c8..f3ea38f44 100644 --- a/apps/openmw/mwrender/activatoranimation.hpp +++ b/apps/openmw/mwrender/activatoranimation.hpp @@ -15,8 +15,6 @@ namespace MWRender public: ActivatorAnimation(const MWWorld::Ptr& ptr); virtual ~ActivatorAnimation(); - - virtual void runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cfc72de37..f9fa6e14c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -125,16 +125,17 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) } -void Animation::updatePosition(float time) +Ogre::Vector3 Animation::updatePosition(float time) { mAnimState->setTimePosition(time); + Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) { /* Update the animation and get the non-accumulation root's difference from the * last update. */ mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); - Ogre::Vector3 posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; + posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); @@ -150,6 +151,7 @@ void Animation::updatePosition(float time) world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); } } + return posdiff; } void Animation::resetPosition(float time) @@ -212,14 +214,15 @@ void Animation::play(const std::string &groupname, const std::string &start) } } -void Animation::runAnimation(float timepassed) +Ogre::Vector3 Animation::runAnimation(float timepassed) { + Ogre::Vector3 movement = Ogre::Vector3::ZERO; while(mAnimState && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - updatePosition(targetTime); + movement += updatePosition(targetTime); break; } @@ -227,12 +230,13 @@ void Animation::runAnimation(float timepassed) const std::string &evt = mNextKey->second; mNextKey++; - updatePosition(time); + movement += updatePosition(time); timepassed = targetTime - time; if(mController) mController->markerEvent(time, evt); } + return movement; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 32d51775a..dfa2950f3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -34,7 +34,7 @@ protected: /* Updates the animation to the specified time, and moves the mPtr object * based on the change since the last update or reset. */ - void updatePosition(float time); + Ogre::Vector3 updatePosition(float time); /* Updates the animation to the specified time, without moving the mPtr * object. */ void resetPosition(float time); @@ -56,7 +56,7 @@ public: void setAccumulation(const Ogre::Vector3 &accum); void play(const std::string &groupname, const std::string &start); - virtual void runAnimation(float timepassed); + virtual Ogre::Vector3 runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index caa040d95..34b09c0d0 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -8,9 +8,8 @@ #include "../mwbase/world.hpp" -using namespace Ogre; -using namespace NifOgre; -namespace MWRender{ +namespace MWRender +{ CreatureAnimation::~CreatureAnimation() { @@ -55,11 +54,4 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) } } -void CreatureAnimation::runAnimation(float timepassed) -{ - // Placeholder - - Animation::runAnimation(timepassed); -} - } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index 5456f857f..0c277d198 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -15,8 +15,6 @@ namespace MWRender public: CreatureAnimation(const MWWorld::Ptr& ptr); virtual ~CreatureAnimation(); - - virtual void runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f309ee899..432a2f526 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -308,7 +308,7 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int return entities; } -void NpcAnimation::runAnimation(float timepassed) +Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { if(mTimeToChange > .2) { @@ -317,7 +317,7 @@ void NpcAnimation::runAnimation(float timepassed) } mTimeToChange += timepassed; - Animation::runAnimation(timepassed); + return Animation::runAnimation(timepassed); } void NpcAnimation::removeEntities(NifOgre::EntityList &entities) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 161091317..a4e87e722 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -98,7 +98,7 @@ public: MWWorld::InventoryStore& inv, int visibilityFlags); virtual ~NpcAnimation(); - virtual void runAnimation(float timepassed); + virtual Ogre::Vector3 runAnimation(float timepassed); void forceUpdate(); }; From 1cdd64cd9b0c90cc8b0c78e4e21a3cd90c525df3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 17:05:58 -0800 Subject: [PATCH 407/916] Return the animation movement from the character controller. Consequently, dead actors don't move anymore. The doPhysics call apparently isn't moving them. --- apps/openmw/mwmechanics/character.cpp | 19 +++++++++++++++++-- apps/openmw/mwrender/animation.cpp | 10 ---------- apps/openmw/mwrender/animation.hpp | 7 +++---- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ff400b9d1..226f00069 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -120,10 +120,25 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) - mAnimation->runAnimation(duration); + movement += mAnimation->runAnimation(duration); mSkipAnim = false; - return mDirection; + + if(getState() == CharState_SpecialIdle || getState() == CharState_Idle || + getState() == CharState_Dead) + { + // FIXME: mDirection shouldn't influence the movement here. + movement += mDirection; + } + else + { + // FIXME: mDirection should be normalized after setting the speed of + // the animation in setDirection, rather than here. + movement = mDirection.normalisedCopy() * movement.length(); + } + + return movement; } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f9fa6e14c..4d8f9586f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -140,16 +140,6 @@ Ogre::Vector3 Animation::updatePosition(float time) /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->translate(-posdiff); mLastPosition += posdiff; - - if(mPtr.isInCell()) - { - /* Finally, move the object based on how much the non-accumulation root moved. */ - Ogre::Vector3 newpos(mPtr.getRefData().getPosition().pos); - newpos += mInsert->getOrientation() * posdiff; - - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->moveObject(mPtr, newpos.x, newpos.y, newpos.z); - } } return posdiff; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index dfa2950f3..349871f0a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -32,11 +32,10 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; - /* Updates the animation to the specified time, and moves the mPtr object - * based on the change since the last update or reset. */ + /* Updates the animation to the specified time, and returns the movement + * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Updates the animation to the specified time, without moving the mPtr - * object. */ + /* Updates the animation to the specified time, without moving anything. */ void resetPosition(float time); float findStart(const std::string &groupname, const std::string &start); From e33f59e0feb124b5436f9ed1b34bbf43bf5f933f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 17:41:36 -0800 Subject: [PATCH 408/916] Ensure the direction vector is initialized and copied properly --- apps/openmw/mwmechanics/character.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 226f00069..b6adec068 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -30,7 +30,7 @@ namespace MWMechanics { CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -47,7 +47,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(mAnimNames.size() == 0) return; From aecfc0829a70a5539b6e86af91fd73a305888e9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 18:04:00 -0800 Subject: [PATCH 409/916] Implement WalkForward and WalkBack character states --- apps/openmw/mwmechanics/actors.cpp | 16 ++++++++++++++++ apps/openmw/mwmechanics/character.cpp | 12 ++++++++++++ apps/openmw/mwmechanics/character.hpp | 4 ++++ 3 files changed, 32 insertions(+) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 396f34eab..b09bcac4d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -251,6 +251,7 @@ namespace MWMechanics } iter->second.setState(CharState_Dead); + iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -264,7 +265,22 @@ namespace MWMechanics { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { + if(iter->second.getState() == CharState_Dead) + continue; + Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + CharacterState newstate = CharState_Idle; + + if(dir.length() >= 0.1f) + { + if(dir.y < 0.0f) + newstate = CharState_WalkBack; + else + newstate = CharState_WalkForward; + } + + if(iter->second.getState() != newstate) + iter->second.setState(newstate); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b6adec068..f3a1f2fba 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -188,6 +188,18 @@ void CharacterController::setState(CharacterState state) mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, "start"); break; + + case CharState_WalkForward: + mCurrentGroup = "walkforward"; + mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); + mAnimation->play(mCurrentGroup, "start"); + break; + case CharState_WalkBack: + mCurrentGroup = "walkback"; + mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); + mAnimation->play(mCurrentGroup, "start"); + break; + case CharState_Dead: mCurrentGroup = "death1"; mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c151b3b9f..f2651b4cf 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -16,6 +16,10 @@ namespace MWMechanics enum CharacterState { CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, + + CharState_WalkForward, + CharState_WalkBack, + CharState_Dead }; From 0b68953f0d7b4c60e83c2be4e3c3cb4715c0178c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 18 Jan 2013 21:40:47 -0800 Subject: [PATCH 410/916] Scale animation speed using the direction length The direction length doesn't currently give a good speed, but it's something. --- apps/openmw/mwmechanics/character.cpp | 24 ++++++++++++++---------- apps/openmw/mwmechanics/character.hpp | 3 +-- apps/openmw/mwrender/animation.cpp | 2 ++ apps/openmw/mwrender/animation.hpp | 4 ++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f3a1f2fba..ad784d34f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -118,6 +118,17 @@ void CharacterController::markerEvent(float time, const std::string &evt) } +void CharacterController::setDirection(const Ogre::Vector3 &dir) +{ + // HACK: The direction length we get is too large. + float mult = dir.length() / 32.0f; + mult = std::max(1.0f, mult); + if(mAnimation) + mAnimation->setSpeedMult(mult); + mDirection = dir.normalisedCopy(); +} + + Ogre::Vector3 CharacterController::update(float duration) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; @@ -125,17 +136,10 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(getState() == CharState_SpecialIdle || getState() == CharState_Idle || - getState() == CharState_Dead) + if(!(getState() == CharState_SpecialIdle || getState() == CharState_Idle || + getState() == CharState_Dead)) { - // FIXME: mDirection shouldn't influence the movement here. - movement += mDirection; - } - else - { - // FIXME: mDirection should be normalized after setting the speed of - // the animation in setDirection, rather than here. - movement = mDirection.normalisedCopy() * movement.length(); + movement = mDirection * movement.length(); } return movement; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index f2651b4cf..9a82f890d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -54,8 +54,7 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setDirection(const Ogre::Vector3 &dir) - { mDirection = dir; } + void setDirection(const Ogre::Vector3 &dir); void setState(CharacterState state); CharacterState getState() const diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4d8f9586f..a86e14c83 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mAnimSpeedMult(1.0f) { } @@ -207,6 +208,7 @@ void Animation::play(const std::string &groupname, const std::string &start) Ogre::Vector3 Animation::runAnimation(float timepassed) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; + timepassed *= mAnimSpeedMult; while(mAnimState && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 349871f0a..6c8357d59 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,7 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + float mAnimSpeedMult; /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ @@ -54,6 +55,9 @@ public: // should be on the scale of 0 to 1. void setAccumulation(const Ogre::Vector3 &accum); + void setSpeedMult(float speedmult) + { mAnimSpeedMult = speedmult; } + void play(const std::string &groupname, const std::string &start); virtual Ogre::Vector3 runAnimation(float timepassed); }; From 2d96f528646e0799837ad29463b97c548f1d3df9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 19 Jan 2013 14:29:14 +0100 Subject: [PATCH 411/916] select correct record when opening a dialogue sub view --- apps/opencs/view/world/dialoguesubview.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 6138fd3f5..2bf6577b1 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -10,6 +10,7 @@ #include #include "../../model/world/columnbase.hpp" +#include "../../model/world/idtable.hpp" CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete) @@ -83,7 +84,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM } } - mWidgetMapper->toFirst(); /// \todo use the correct row instead + mWidgetMapper->setCurrentModelIndex ( + dynamic_cast (*model).getModelIndex (id.getId(), 0)); } void CSVWorld::DialogueSubView::setEditLock (bool locked) From de2d084e6182b5c9ff328491f32a43f28b6624a9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 14:22:15 -0800 Subject: [PATCH 412/916] Add a looping property to handle if an animation should loop --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- apps/openmw/mwmechanics/character.cpp | 15 +++++++++------ apps/openmw/mwmechanics/character.hpp | 5 +++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index b09bcac4d..76e02ed36 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,9 +169,9 @@ namespace MWMechanics /* Kind of a hack. Activators need a character controller to manage an idle state. */ if(ptr.getTypeName() == typeid(ESM::Activator).name() || !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); else - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -213,7 +213,7 @@ namespace MWMechanics if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) - iter->second.setState(CharState_Idle); + iter->second.setState(CharState_Idle, true); updateActor(iter->first, totalDuration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) @@ -250,7 +250,7 @@ namespace MWMechanics continue; } - iter->second.setState(CharState_Dead); + iter->second.setState(CharState_Dead, false); iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -280,7 +280,7 @@ namespace MWMechanics } if(iter->second.getState() != newstate) - iter->second.setState(newstate); + iter->second.setState(newstate, true); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ad784d34f..5127b6564 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,8 +29,8 @@ namespace MWMechanics { -CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) +CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { if(mAnimation) mAnimNames = mAnimation->getAnimationNames(); @@ -41,13 +41,14 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - setState(mState); + setState(mState, loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mLoop(rhs.mLoop) { if(mAnimNames.size() == 0) return; @@ -81,7 +82,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) { if(mAnimQueue.size() == 0) { - if(time > 0.0f && mState != CharState_Dead) + if(time > 0.0f && mLoop) mAnimation->play(mCurrentGroup, "loop start"); } else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) @@ -96,7 +97,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) { if(mAnimQueue.size() == 0) { - if(time > 0.0f && mState != CharState_Dead) + if(time > 0.0f && mLoop) mAnimation->play(mCurrentGroup, "loop start"); } else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) @@ -158,6 +159,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; + mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); } @@ -176,9 +178,10 @@ void CharacterController::skipAnim() } -void CharacterController::setState(CharacterState state) +void CharacterController::setState(CharacterState state, bool loop) { mState = state; + mLoop = loop; if(mAnimNames.size() == 0) return; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9a82f890d..d773c85b2 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -38,6 +38,7 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; + bool mLoop; protected: /* Called by the animation whenever a new text key is reached. */ @@ -46,7 +47,7 @@ protected: friend class MWRender::Animation; public: - CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state); + CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); Ogre::Vector3 update(float duration); @@ -56,7 +57,7 @@ public: void setDirection(const Ogre::Vector3 &dir); - void setState(CharacterState state); + void setState(CharacterState state, bool loop); CharacterState getState() const { return mState; } }; From a8e02779b26e0e7b21761b3489ae58917b28181d Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 19 Jan 2013 23:33:18 +0100 Subject: [PATCH 413/916] - Add support for multiple plugins trying to modify the same reference - Fix a small signed/unsigned warning --- apps/openmw/mwworld/cellstore.cpp | 56 +++++++++++++++++++++++ apps/openmw/mwworld/esmstore.cpp | 6 +-- apps/openmw/mwworld/esmstore.hpp | 3 ++ apps/openmw/mwworld/store.hpp | 45 ++++++++++++++++--- components/esm/loadcell.cpp | 74 ++++++++++++++++++++++++------- components/esm/loadcell.hpp | 46 ++++++++++++++++++- 6 files changed, 203 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index d007ff981..ecc1bc306 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -96,6 +96,11 @@ namespace MWWorld // Get each reference in turn while(mCell->getNextRef(esm[index], ref)) { + // Don't load reference if it was moved to a different cell. + if (mCell->mMovedRefs.find(ref.mRefnum) != mCell->mMovedRefs.end()) { + continue; + } + std::string lowerCase; std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), @@ -139,5 +144,56 @@ namespace MWWorld } } } + + // Load moved references, from separately tracked list. + for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); it++) + { + // Doesn't seem to work in one line... huh? Too sleepy to check... + //const ESM::CellRef &ref0 = it->second; + ESM::CellRef &ref = const_cast(it->second); + + std::string lowerCase; + + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + int rec = store.find(ref.mRefID); + + ref.mRefID = lowerCase; + + /* We can optimize this further by storing the pointer to the + record itself in store.all, so that we don't need to look it + up again here. However, never optimize. There are infinite + opportunities to do that later. + */ + switch(rec) + { + case ESM::REC_ACTI: mActivators.load(ref, store); break; + case ESM::REC_ALCH: mPotions.load(ref, store); break; + case ESM::REC_APPA: mAppas.load(ref, store); break; + case ESM::REC_ARMO: mArmors.load(ref, store); break; + case ESM::REC_BOOK: mBooks.load(ref, store); break; + case ESM::REC_CLOT: mClothes.load(ref, store); break; + case ESM::REC_CONT: mContainers.load(ref, store); break; + case ESM::REC_CREA: mCreatures.load(ref, store); break; + case ESM::REC_DOOR: mDoors.load(ref, store); break; + case ESM::REC_INGR: mIngreds.load(ref, store); break; + case ESM::REC_LEVC: mCreatureLists.load(ref, store); break; + case ESM::REC_LEVI: mItemLists.load(ref, store); break; + case ESM::REC_LIGH: mLights.load(ref, store); break; + case ESM::REC_LOCK: mLockpicks.load(ref, store); break; + case ESM::REC_MISC: mMiscItems.load(ref, store); break; + case ESM::REC_NPC_: mNpcs.load(ref, store); break; + case ESM::REC_PROB: mProbes.load(ref, store); break; + case ESM::REC_REPA: mRepairs.load(ref, store); break; + case ESM::REC_STAT: mStatics.load(ref, store); break; + case ESM::REC_WEAP: mWeapons.load(ref, store); break; + + case 0: std::cout << "Cell reference " + ref.mRefID + " not found!\n"; break; + default: + std::cout << "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n"; + } + + } } } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 54050b38c..38fadca9e 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -30,13 +30,13 @@ void ESMStore::load(ESM::ESMReader &esm) // Cache parent esX files by tracking their indices in the global list of // all files/readers used by the engine. This will greaty help to accelerate // parsing of reference IDs. - size_t index = ~0; + int index = ~0; const ESM::ESMReader::MasterList &masters = esm.getMasters(); std::vector *allPlugins = esm.getGlobalReaderList(); for (size_t j = 0; j < masters.size(); j++) { ESM::MasterData &mast = const_cast(masters[j]); std::string fname = mast.name; - for (size_t i = 0; i < esm.getIndex(); i++) { + for (int i = 0; i < esm.getIndex(); i++) { const std::string &candidate = allPlugins->at(i).getContext().filename; std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); if (fname == fnamecandidate) { @@ -44,7 +44,7 @@ void ESMStore::load(ESM::ESMReader &esm) break; } } - if (index == (size_t)~0) { + if (index == (int)~0) { // Tried to load a parent file that has not been loaded yet. This is bad, // the launcher should have taken care of this. std::string fstring = "File " + fname + " asks for parent file " + masters[j].name diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index bd8e003f4..2039a00db 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -94,6 +94,9 @@ namespace MWWorld ESMStore() : mDynamicCount(0) { + // Cell store needs access to this for tracking moved references + mCells.mEsmStore = this; + mStores[ESM::REC_ACTI] = &mActivators; mStores[ESM::REC_ALCH] = &mPotions; mStores[ESM::REC_APPA] = &mAppas; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 77c9c7357..c36e84813 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -399,8 +399,7 @@ namespace MWWorld DynamicInt mDynamicInt; DynamicExt mDynamicExt; - - + const ESM::Cell *search(const ESM::Cell &cell) const { if (cell.isExterior()) { return search(cell.getGridX(), cell.getGridY()); @@ -409,6 +408,8 @@ namespace MWWorld } public: + ESMStore *mEsmStore; + typedef SharedIterator iterator; Store() @@ -450,6 +451,30 @@ namespace MWWorld return 0; } + const ESM::Cell *searchOrCreate(int x, int y) { + ESM::Cell cell; + cell.mData.mX = x, cell.mData.mY = y; + + std::pair key(x, y); + std::map, ESM::Cell>::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); + } + + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + ESM::Cell *newCell = new ESM::Cell; + newCell->mData.mX = x; + newCell->mData.mY = y; + mExt[std::make_pair(x, y)] = *newCell; + delete newCell; + + return &mExt[std::make_pair(x, y)]; + } + const ESM::Cell *find(const std::string &id) const { const ESM::Cell *ptr = search(id); if (ptr == 0) { @@ -500,7 +525,7 @@ namespace MWWorld cell->mName = id; // The cell itself takes care of all the hairy details - cell->load(esm); + cell->load(esm, *mEsmStore); if(cell->mData.mFlags & ESM::Cell::Interior) { @@ -515,7 +540,6 @@ namespace MWWorld *oldcell = *cell; } else mInt[idLower] = *cell; - delete cell; } else { @@ -526,12 +550,23 @@ namespace MWWorld oldcell->mContextList.push_back(cell->mContextList.at(0)); // copy list into new cell cell->mContextList = oldcell->mContextList; + // merge lists of leased references, use newer data in case of conflict + for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) { + // remove reference from current leased ref tracker and add it to new cell + if (oldcell->mMovedRefs.find(it->second.mRefnum) != oldcell->mMovedRefs.end()) { + ESM::MovedCellRef target0 = oldcell->mMovedRefs[it->second.mRefnum]; + ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); + wipecell->mLeasedRefs.erase(it->second.mRefnum); + } + oldcell->mMovedRefs[it->second.mRefnum] = it->second; + } + cell->mMovedRefs = oldcell->mMovedRefs; // have new cell replace old cell *oldcell = *cell; } else mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; - delete cell; } + delete cell; } iterator intBegin() const { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index aafe629e6..76a1e4f95 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -2,11 +2,15 @@ #include #include -#include +#include +#include #include "esmreader.hpp" #include "esmwriter.hpp" +#include +#include + namespace ESM { @@ -64,10 +68,11 @@ void CellRef::save(ESMWriter &esm) } } -void Cell::load(ESMReader &esm) +void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) { // Ignore this for now, it might mean we should delete the entire // cell? + // TODO: treat the special case "another plugin moved this ref, but we want to delete it"! if (esm.isNextSub("DELE")) { esm.skipHSub(); } @@ -110,6 +115,33 @@ void Cell::load(ESMReader &esm) if (esm.isNextSub("NAM0")) { esm.getHT(mNAM0); } + + // preload moved references + while (esm.isNextSub("MVRF")) { + CellRef ref; + MovedCellRef cMRef; + getNextMVRF(esm, cMRef); + + MWWorld::Store &cStore = const_cast&>(store.get()); + ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following + // implementation when the oher implementation works as well. + getNextRef(esm, ref); + std::string lowerCase; + + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + // Add data required to make reference appear in the correct cell. + /* + std::cout << "Moving refnumber! First cell: " << mData.mX << " " << mData.mY << std::endl; + std::cout << " New cell: " << cMRef.mTarget[0] << " " << cMRef.mTarget[0] << std::endl; + std::cout << "Refnumber (MVRF): " << cMRef.mRefnum << " (FRMR) " << ref.mRefnum << std::endl; + */ + mMovedRefs[cMRef.mRefnum] = cMRef; + cellAlt->mLeasedRefs[ref.mRefnum] = ref; + } // Save position of the cell references and move on mContextList.push_back(esm.getContext()); @@ -171,23 +203,15 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // TODO: Try and document reference numbering, I don't think this has been done anywhere else. if (!esm.hasMoreSubs()) return false; - + + // NOTE: We should not need this check. It is a safety check until we have checked + // more plugins, and how they treat these moved references. if (esm.isNextSub("MVRF")) { - // Moved existing reference across cell boundaries, so interpret the blocks correctly. - // FIXME: Right now, we don't do anything with this data. This might result in weird behaviour, - // where a moved reference does not appear because the owning cell (i.e. this cell) is not - // loaded in memory. - int movedRefnum = 0; - int destCell[2]; - esm.getHT(movedRefnum); - esm.getHNT(destCell, "CNDT"); - // TODO: Figure out what happens when a reference has moved into an interior cell. This might - // be required for NPCs following the player. + esm.skipRecord(); // skip MVRF + esm.skipRecord(); // skip CNDT + // That should be it, I haven't seen any other fields yet. } - // If we have just parsed a MVRF entry, there should be a regular FRMR entry following right there. - // With the exception that this bock technically belongs to a different cell than this one. - // TODO: Figure out a way to handle these weird references that do not belong to this cell. - // This may require some not-so-small behing-the-scenes updates. + esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); @@ -293,4 +317,20 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) return true; } +bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) +{ + esm.getHT(mref.mRefnum); + esm.getHNOT(mref.mTarget, "CNDT"); + + // Identify references belonging to a parent file and adapt the ID accordingly. + int local = (mref.mRefnum & 0xff000000) >> 24; + size_t global = esm.getIndex() + 1; + mref.mRefnum &= 0x00ffffff; // delete old plugin ID + const ESM::ESMReader::MasterList &masters = esm.getMasters(); + global = masters[local-1].index + 1; + mref.mRefnum |= global << 24; // insert global plugin ID + + return true; +} + } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index dff5a3338..6862dbc5c 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -6,6 +6,14 @@ #include "esmcommon.hpp" #include "defs.hpp" +#include + +/* +namespace MWWorld { + class ESMStore; + class CellStore; +} +*/ namespace ESM { @@ -86,6 +94,26 @@ public: void save(ESMWriter &esm); }; +/* Moved cell reference tracking object. This mainly stores the target cell + of the reference, so we can easily know where it has been moved when another + plugin tries to move it independently. + */ +class MovedCellRef +{ +public: + int mRefnum; + + // Target cell (if exterior) + int mTarget[2]; + + // TODO: Support moving references between exterior and interior cells! + // This may happen in saves, when an NPC follows the player. Tribunal + // introduces a henchman (which no one uses), so we may need this as well. +}; + +typedef std::map MovedCellRefTracker; +typedef std::map CellRefTracker; + /* Cells hold data about objects, creatures, statics (rocks, walls, buildings) and landscape (for exterior cells). Cells frequently also has other associated LAND and PGRD records. Combined, all this @@ -131,8 +159,17 @@ struct Cell bool mWaterInt; int mMapColor; int mNAM0; - - void load(ESMReader &esm); + + // References "leased" from another cell (i.e. a different cell + // introduced this ref, and it has been moved here by a plugin) + CellRefTracker mLeasedRefs; + MovedCellRefTracker mMovedRefs; + + void load(ESMReader &esm, MWWorld::ESMStore &store); + + // This method is left in for compatibility with esmtool. Parsing moved references currently requires + // passing ESMStore, bit it does not know about this parameter, so we do it this way. + void load(ESMReader &esm) {}; void save(ESMWriter &esm); bool isExterior() const @@ -167,6 +204,11 @@ struct Cell reuse one memory location without blanking it between calls. */ static bool getNextRef(ESMReader &esm, CellRef &ref); + + /* This fetches an MVRF record, which is used to track moved references. + * Since they are comparably rare, we use a separate method for this. + */ + static bool getNextMVRF(ESMReader &esm, MovedCellRef &mref); }; } #endif From e0541b52c4321a8535516590de0df40ec0d98436 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 14:56:24 -0800 Subject: [PATCH 414/916] Use a list to store and get state information --- apps/openmw/mwmechanics/character.cpp | 67 ++++++++++++++++----------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5127b6564..a49400823 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -19,6 +19,8 @@ #include "character.hpp" +#include + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" @@ -29,6 +31,35 @@ namespace MWMechanics { +static const struct { + CharacterState state; + const char groupname[32]; + Ogre::Vector3 accumulate; +} sStateList[] = { + { CharState_SpecialIdle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle, "idle", Ogre::Vector3::ZERO }, + + { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + + { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, +}; +static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); + +static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 *accum) +{ + for(size_t i = 0;i < sStateListSize;i++) + { + if(sStateList[i].state == state) + { + *group = sStateList[i].groupname; + *accum = sStateList[i].accumulate; + return; + } + } + throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(state)); +} + CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { @@ -41,7 +72,11 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } mAnimation->setController(this); - setState(mState, loop); + + Ogre::Vector3 accum; + getStateInfo(mState, &mCurrentGroup, &accum); + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "stop"); } CharacterController::CharacterController(const CharacterController &rhs) @@ -186,33 +221,11 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimNames.size() == 0) return; mAnimQueue.clear(); - switch(mState) - { - case CharState_SpecialIdle: - break; - case CharState_Idle: - mCurrentGroup = "idle"; - mAnimation->setAccumulation(Ogre::Vector3::ZERO); - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_WalkForward: - mCurrentGroup = "walkforward"; - mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - case CharState_WalkBack: - mCurrentGroup = "walkback"; - mAnimation->setAccumulation(Ogre::Vector3(0.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - - case CharState_Dead: - mCurrentGroup = "death1"; - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); - mAnimation->play(mCurrentGroup, "start"); - break; - } + Ogre::Vector3 accum; + getStateInfo(mState, &mCurrentGroup, &accum); + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "start"); } } From a7b07ee5cf2ed697ce43dbe0283ac7554c106010 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 15:44:57 -0800 Subject: [PATCH 415/916] Don't reset the animation when setting the same state Unless looping is being toggled on. --- apps/openmw/mwmechanics/actors.cpp | 3 +-- apps/openmw/mwmechanics/character.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 76e02ed36..8c6da4a31 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -279,8 +279,7 @@ namespace MWMechanics newstate = CharState_WalkForward; } - if(iter->second.getState() != newstate) - iter->second.setState(newstate, true); + iter->second.setState(newstate, true); iter->second.setDirection(dir); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a49400823..7e52ef3d8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -215,8 +215,18 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { - mState = state; - mLoop = loop; + if(mState == state) + { + // If setting the same state again, only reset the animation if looping + // is being turned on. + if(mLoop == loop || !(mLoop=loop)) + return; + } + else + { + mState = state; + mLoop = loop; + } if(mAnimNames.size() == 0) return; From d6b956cdcf45715329d080deb0783c74244821dd Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 15 Jan 2013 08:27:58 -0800 Subject: [PATCH 416/916] fixed swapped day & month fields when created a stamped journal entry --- apps/openmw/mwdialogue/journalentry.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index e6141884c..5ffde5499 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -61,8 +61,8 @@ namespace MWDialogue StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index) { int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong; - int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong; - int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong; + int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong; + int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong; return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth); } From 68779375b2aa6dd1e722d2460c15d37a17403aed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 16:19:47 -0800 Subject: [PATCH 417/916] Implement WalkLeft and WalkRight character states --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++++- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwmechanics/character.hpp | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8c6da4a31..6c69c457b 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -273,7 +273,14 @@ namespace MWMechanics if(dir.length() >= 0.1f) { - if(dir.y < 0.0f) + if(std::abs(dir.x/2.0f) > std::abs(dir.y)) + { + if(dir.x > 0.0f) + newstate = CharState_WalkRight; + else if(dir.x < 0.0f) + newstate = CharState_WalkLeft; + } + else if(dir.y < 0.0f) newstate = CharState_WalkBack; else newstate = CharState_WalkForward; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7e52ef3d8..262945c02 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -41,6 +41,8 @@ static const struct { { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, + { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, + { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, }; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d773c85b2..6d8b3386c 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -19,6 +19,8 @@ enum CharacterState { CharState_WalkForward, CharState_WalkBack, + CharState_WalkLeft, + CharState_WalkRight, CharState_Dead }; From 528c3da6dae85a8c4c1903b16b3322742ca02292 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 19 Jan 2013 16:20:22 -0800 Subject: [PATCH 418/916] record heard topics in journal --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index b83f495ad..a3bb640e6 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -20,6 +20,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/journal.hpp" #include "../mwbase/scriptmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -269,6 +270,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + MWBase::Environment::get().getJournal()->addTopic (topic, info->mId); executeScript (info->mResultScript); @@ -420,6 +422,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); + MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); executeScript (info->mResultScript); mLastTopic = mLastTopic; mLastDialogue = *info; From 4c7ae3d1ff296b4c7cc96fcd2c533de3ace00443 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 19 Jan 2013 16:21:15 -0800 Subject: [PATCH 419/916] prevent duplicate journal entries from being recorded --- apps/openmw/mwdialogue/journalimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 2b2c60381..c623ddc85 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -31,6 +31,12 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index) { + // bail out of we already have heard this... + auto infoId = JournalEntry::idFromIndex (id, index); + for (auto i = mJournal.begin (); i != mJournal.end (); ++i) + if (i->mTopic == id && i->mInfoId == infoId) + return; + StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index); mJournal.push_back (entry); From f55da179337a2591438f8ccad5cd9231203dce77 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 19 Jan 2013 16:21:41 -0800 Subject: [PATCH 420/916] made some journal accessor methods constant --- apps/openmw/mwdialogue/topic.cpp | 6 +++--- apps/openmw/mwdialogue/topic.hpp | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index b6e7c07ae..3253b20d6 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -27,17 +27,17 @@ namespace MWDialogue mEntries.push_back (entry.mInfoId); } - Topic::TEntryIter Topic::begin() + Topic::TEntryIter Topic::begin() const { return mEntries.begin(); } - Topic::TEntryIter Topic::end() + Topic::TEntryIter Topic::end() const { return mEntries.end(); } - JournalEntry Topic::getEntry (const std::string& infoId) + JournalEntry Topic::getEntry (const std::string& infoId) const { return JournalEntry (mTopic, infoId); } diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp index 566f60ab0..c3f0baabc 100644 --- a/apps/openmw/mwdialogue/topic.hpp +++ b/apps/openmw/mwdialogue/topic.hpp @@ -34,13 +34,15 @@ namespace MWDialogue /// /// \note Redundant entries are ignored. - TEntryIter begin(); + std::string const & getName () const { return mTopic; } + + TEntryIter begin() const; ///< Iterator pointing to the begin of the journal for this topic. - TEntryIter end(); + TEntryIter end() const; ///< Iterator pointing past the end of the journal for this topic. - JournalEntry getEntry (const std::string& infoId); + JournalEntry getEntry (const std::string& infoId) const; }; } From 85ca1e993f312594f4e0a77b12d3be625f218f46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 19 Jan 2013 21:55:04 -0800 Subject: [PATCH 421/916] Properly check if an animation exists before playing it --- apps/openmw/mwmechanics/character.cpp | 34 +++++++++++++-------------- apps/openmw/mwmechanics/character.hpp | 2 -- apps/openmw/mwrender/animation.cpp | 18 +++----------- apps/openmw/mwrender/animation.hpp | 3 ++- 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 262945c02..ea934a284 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -65,29 +65,24 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) { - if(mAnimation) - mAnimNames = mAnimation->getAnimationNames(); - if(mAnimNames.size() == 0) - { - mAnimation = NULL; + if(!mAnimation) return; - } mAnimation->setController(this); Ogre::Vector3 accum; getStateInfo(mState, &mCurrentGroup, &accum); mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "stop"); + if(mAnimation->hasAnimation(mCurrentGroup)) + mAnimation->play(mCurrentGroup, "stop"); } CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimNames(rhs.mAnimNames) - , mAnimQueue(rhs.mAnimQueue), mCurrentGroup(rhs.mCurrentGroup) - , mDirection(rhs.mDirection), mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) - , mLoop(rhs.mLoop) + : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) + , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim), mLoop(rhs.mLoop) { - if(mAnimNames.size() == 0) + if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); @@ -186,7 +181,7 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - if(std::find(mAnimNames.begin(), mAnimNames.end(), groupname) != mAnimNames.end()) + if(mAnimation && mAnimation->hasAnimation(groupname)) { count = std::max(count, 1); if(mode != 0 || mAnimQueue.size() == 0) @@ -230,14 +225,19 @@ void CharacterController::setState(CharacterState state, bool loop) mLoop = loop; } - if(mAnimNames.size() == 0) + if(!mAnimation) return; mAnimQueue.clear(); + std::string anim; Ogre::Vector3 accum; - getStateInfo(mState, &mCurrentGroup, &accum); - mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "start"); + getStateInfo(mState, &anim, &accum); + if(mAnimation->hasAnimation(anim)) + { + mCurrentGroup = anim; + mAnimation->setAccumulation(accum); + mAnimation->play(mCurrentGroup, "start"); + } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 6d8b3386c..43ff21dfb 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -30,8 +30,6 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - std::vector mAnimNames; - typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a86e14c83..67be0bf0c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -100,17 +100,9 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model } -std::vector Animation::getAnimationNames() +bool Animation::hasAnimation(const std::string &anim) { - std::vector anims; - if(mEntityList.mSkelBase) - { - Ogre::AnimationStateSet *as = mEntityList.mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator ai = as->getAnimationStateIterator(); - while(ai.hasMoreElements()) - anims.push_back(ai.getNext()->getAnimationName()); - } - return anims; + return mEntityList.mSkelBase && mEntityList.mSkelBase->hasAnimationState(anim); } @@ -188,13 +180,9 @@ float Animation::findStart(const std::string &groupname, const std::string &star void Animation::play(const std::string &groupname, const std::string &start) { try { - if(!mEntityList.mSkelBase) - throw std::runtime_error("Attempting to animate an inanimate object"); - - Ogre::AnimationState *newstate = mEntityList.mSkelBase->getAnimationState(groupname); if(mAnimState) mAnimState->setEnabled(false); - mAnimState = newstate; + mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); mCurrentKeys = &mTextKeys[groupname]; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6c8357d59..50ddc34d5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -48,7 +48,8 @@ public: virtual ~Animation(); void setController(MWMechanics::CharacterController *controller); - std::vector getAnimationNames(); + + bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just // move visually, but not affect the actual movement. Each x/y/z value From 3c6ddd7fa783068477a5d0e91605b2037803558e Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 14:10:04 +0000 Subject: [PATCH 422/916] fixed isInCell method --- apps/openmw/mwworld/containerstore.cpp | 1 + apps/openmw/mwworld/ptr.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 6884aa6c8..7a4120d0a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -90,6 +90,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) cell = player.getCell(); item.mCell = cell; + item.mContainerStore = 0; MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); } diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 594ddef2d..d97ebcc6e 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -74,7 +74,7 @@ namespace MWWorld bool isInCell() const { - return (mCell != 0); + return (mContainerStore == 0); } void setContainerStore (ContainerStore *store); From 665a530e10c912e5159929f7e4fcb5300d9559a4 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 14:14:34 +0000 Subject: [PATCH 423/916] renamed realAdd to addImp --- apps/openmw/mwworld/containerstore.cpp | 6 +++--- apps/openmw/mwworld/containerstore.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 7a4120d0a..bca4073b5 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -74,7 +74,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) { - MWWorld::ContainerStoreIterator it = realAdd(ptr); + MWWorld::ContainerStoreIterator it = addImp(ptr); MWWorld::Ptr item = *it; std::string script = MWWorld::Class::get(item).getScript(item); @@ -97,7 +97,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) return it; } -MWWorld::ContainerStoreIterator MWWorld::ContainerStore::realAdd (const Ptr& ptr) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) { int type = getType(ptr); @@ -189,7 +189,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor } ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) - realAdd (ref.getPtr()); + addImp (ref.getPtr()); } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e274ee130..e4f75d547 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -52,7 +52,7 @@ namespace MWWorld int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; - ContainerStoreIterator realAdd (const Ptr& ptr); + ContainerStoreIterator addImp (const Ptr& ptr); public: From abe25c5f662def09b98ac7afe076258e439294a0 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 14:24:55 +0000 Subject: [PATCH 424/916] removed use of c++11 auto --- apps/openmw/mwdialogue/journalimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index c623ddc85..5e2bc6bc0 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -32,8 +32,8 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index) { // bail out of we already have heard this... - auto infoId = JournalEntry::idFromIndex (id, index); - for (auto i = mJournal.begin (); i != mJournal.end (); ++i) + std::string infoId = JournalEntry::idFromIndex (id, index); + for (TEntryIter i = mJournal.begin (); i != mJournal.end (); ++i) if (i->mTopic == id && i->mInfoId == infoId) return; From bbac63bff7cd2f16f00c2c9cde102f1dbdbb7c02 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 14:25:44 +0000 Subject: [PATCH 425/916] Ignore vim swap files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9734ac35c..776e2b659 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ makefile data *.kdev4 CMakeLists.txt.user +*.swp +*.swo From 28c580d2805ee7a88a6a00b2fae573eac3f8807f Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 15:43:52 +0000 Subject: [PATCH 426/916] disabling and enabling containers causes scripts on contents to be disabled and enabled accordingly --- apps/openmw/mwworld/worldimp.cpp | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 716cd6e96..bd48875e7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -406,6 +406,24 @@ namespace MWWorld if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); + + /* run scripts on container contents */ + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + item.mCell = reference.getCell(); + mLocalScripts.add (script, item); + } + } + } if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); @@ -417,6 +435,23 @@ namespace MWWorld if (reference.getRefData().isEnabled()) { reference.getRefData().disable(); + + /* remove scripts on container contents */ + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + mLocalScripts.remove (item); + } + } + } if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); From 23dada0ee4e4d35ff14983a6ff515b30d228b7cb Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 16:38:56 +0000 Subject: [PATCH 427/916] moved script handling on enable / disable into their own functions --- apps/openmw/mwworld/worldimp.cpp | 76 ++++++++++++++++++-------------- apps/openmw/mwworld/worldimp.hpp | 3 ++ 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index bd48875e7..ee18e5d95 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -401,34 +401,57 @@ namespace MWWorld return MWWorld::Ptr(); } + void World::addContainerScripts(const Ptr& reference, Ptr::CellStore * cell) + { + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + item.mCell = cell; + mLocalScripts.add (script, item); + } + } + } + } + void World::enable (const Ptr& reference) { if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); - /* run scripts on container contents */ - if( reference.getTypeName()==typeid (ESM::Container).name() || - reference.getTypeName()==typeid (ESM::NPC).name() || - reference.getTypeName()==typeid (ESM::Creature).name()) - { - MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); - for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) - { - std::string script = MWWorld::Class::get(*it).getScript(*it); - if(script != "") - { - MWWorld::Ptr item = *it; - item.mCell = reference.getCell(); - mLocalScripts.add (script, item); - } - } - } + addContainerScripts(reference, reference.getCell()); if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); } } + + void World::removeContainerScripts(const Ptr& reference) + { + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + mLocalScripts.remove (item); + } + } + } + } void World::disable (const Ptr& reference) { @@ -436,22 +459,9 @@ namespace MWWorld { reference.getRefData().disable(); - /* remove scripts on container contents */ - if( reference.getTypeName()==typeid (ESM::Container).name() || - reference.getTypeName()==typeid (ESM::NPC).name() || - reference.getTypeName()==typeid (ESM::Creature).name()) - { - MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); - for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) - { - std::string script = MWWorld::Class::get(*it).getScript(*it); - if(script != "") - { - MWWorld::Ptr item = *it; - mLocalScripts.remove (item); - } - } - } + removeContainerScripts(reference); + if(MWWorld::Class::get(reference).getScript(reference) != "") + mLocalScripts.remove(reference); if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 905e6fd96..fa5b41038 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -105,6 +105,9 @@ namespace MWWorld float getNpcActivationDistance (); float getObjectActivationDistance (); + void removeContainerScripts(const Ptr& reference); + void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell); + public: World (OEngine::Render::OgreRenderer& renderer, From 951eb1b236b600ad6c35888649c79bbe8b59e5e8 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 16 Jan 2013 20:10:20 +0100 Subject: [PATCH 428/916] Dialogue: return a response from "Info Refusal" when disposition is not satisfied --- apps/openmw/mwdialogue/filter.cpp | 42 +++++++++++++++++++++++++------ apps/openmw/mwdialogue/filter.hpp | 32 +++++++++++------------ 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 99be5554a..d515c3ac4 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -121,6 +121,13 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const return true; } +bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const +{ + int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + + return actorDisposition >= info.mData.mDisposition; +} + bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name()) @@ -547,17 +554,38 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) {} -bool MWDialogue::Filter::operator() (const ESM::DialInfo& info) const -{ - return testActor (info) && testPlayer (info) && testSelectStructs (info); -} - const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const { + bool infoRefusal = false; + + // Iterate over topic responses to find a matching one for (std::vector::const_iterator iter = dialogue.mInfo.begin(); iter!=dialogue.mInfo.end(); ++iter) - if ((*this) (*iter)) - return &*iter; + { + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) + { + if (testDisposition (*iter)) + return &*iter; + else + infoRefusal = true; + } + } + + if (infoRefusal) + { + // No response is valid because of low NPC disposition, + // search a response in the topic "Info Refusal" + + const MWWorld::Store &dialogues = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Dialogue& infoRefusalDialogue = *dialogues.find ("Info Refusal"); + + for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); + iter!=infoRefusalDialogue.mInfo.end(); ++iter) + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) + return &*iter; + } return 0; } diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 7c8f1116f..aa8934bfc 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -18,39 +18,39 @@ namespace MWDialogue MWWorld::Ptr mActor; int mChoice; bool mTalkedToPlayer; - + bool testActor (const ESM::DialInfo& info) const; ///< Is this the right actor for this \a info? - + bool testPlayer (const ESM::DialInfo& info) const; ///< Do the player and the cell the player is currently in match \a info? - + bool testSelectStructs (const ESM::DialInfo& info) const; ///< Are all select structs matching? - + + bool testDisposition (const ESM::DialInfo& info) const; + ///< Is the actor disposition toward the player high enough? + bool testSelectStruct (const SelectWrapper& select) const; - + bool testSelectStructNumeric (const SelectWrapper& select) const; - + int getSelectStructInteger (const SelectWrapper& select) const; - + bool getSelectStructBoolean (const SelectWrapper& select) const; - + int getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const; - + bool hasFactionRankSkillRequirements (const MWWorld::Ptr& actor, const std::string& factionId, int rank) const; bool hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, const std::string& factionId, int rank) const; - - public: - - Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - bool operator() (const ESM::DialInfo& info) const; - ///< \return does the dialogue match? - + public: + + Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); + const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const; }; } From 05796d85a4e4d659ba4a0d61f5e7fa6be3dfacb3 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 19 Jan 2013 02:43:55 +0100 Subject: [PATCH 429/916] NPC: take stats from NPDT12 into account Some available stats (level, reputation and disposition) were not used for NPC with auto-calculated stats. --- apps/openmw/mwclass/npc.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 586f9638d..cfbc64b87 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -100,14 +100,15 @@ namespace MWClass } else { - /// \todo do something with mNpdt12 maybe:p for (int i=0; i<8; ++i) data->mCreatureStats.getAttribute (i).set (10); for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); - data->mCreatureStats.setLevel (1); + data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 43e85ea0c65301c28f83b053ca65847460815e72 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 20 Jan 2013 01:54:35 +0100 Subject: [PATCH 430/916] Disallow redirection to info refusal for greetings --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 9 +++++---- apps/openmw/mwdialogue/filter.cpp | 15 +++++++++++++-- apps/openmw/mwdialogue/filter.hpp | 7 ++++++- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index a3bb640e6..a8e6a98c9 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -139,7 +139,8 @@ namespace MWDialogue { if(it->mType == ESM::Dialogue::Greeting) { - if (const ESM::DialInfo *info = filter.search (*it)) + // Search a response (we do not accept a fallback to "Info refusal" here) + if (const ESM::DialInfo *info = filter.search (*it, false)) { //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); @@ -248,7 +249,7 @@ namespace MWDialogue const ESM::Dialogue& dialogue = *dialogues.find (topic); - if (const ESM::DialInfo *info = filter.search (dialogue)) + if (const ESM::DialInfo *info = filter.search (dialogue, true)) { parseText (info->mResponse); @@ -295,7 +296,7 @@ namespace MWDialogue { if (iter->mType == ESM::Dialogue::Topic) { - if (filter.search (*iter)) + if (filter.responseAvailable (*iter)) { std::string lower = Misc::StringUtils::lowerCase(iter->mId); mActorKnownTopics.push_back (lower); @@ -412,7 +413,7 @@ namespace MWDialogue { Filter filter (mActor, mChoice, mTalkedTo); - if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic])) + if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true)) { mChoiceMap.clear(); mChoice = -1; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index d515c3ac4..5d56e94b0 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -554,7 +554,7 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) {} -const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) const +const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const { bool infoRefusal = false; @@ -571,7 +571,7 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) } } - if (infoRefusal) + if (infoRefusal && fallbackToInfoRefusal) { // No response is valid because of low NPC disposition, // search a response in the topic "Info Refusal" @@ -590,3 +590,14 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue) return 0; } +bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const +{ + for (std::vector::const_iterator iter = dialogue.mInfo.begin(); + iter!=dialogue.mInfo.end(); ++iter) + { + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) + return true; + } + + return false; +} diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index aa8934bfc..707c0154b 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -51,7 +51,12 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - const ESM::DialInfo *search (const ESM::Dialogue& dialogue) const; + const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; + ///< Get a matching response for the requested dialogue. + /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. + + bool responseAvailable (const ESM::Dialogue& dialogue) const; + ///< Does a matching response exist? (disposition is ignored for this check) }; } From 736e4716131238669105001cadd10f0308cc1a98 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 20 Jan 2013 15:57:34 +0100 Subject: [PATCH 431/916] Print a fallback text when no topic response is found --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index a8e6a98c9..f548c46f7 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -249,12 +249,12 @@ namespace MWDialogue const ESM::Dialogue& dialogue = *dialogues.find (topic); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + if (const ESM::DialInfo *info = filter.search (dialogue, true)) { parseText (info->mResponse); - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - if (dialogue.mType==ESM::Dialogue::Persuasion) { std::string modifiedTopic = "s" + topic; @@ -278,6 +278,13 @@ namespace MWDialogue mLastTopic = topic; mLastDialogue = *info; } + else + { + // no response found, print a fallback text + win->addTitle (topic); + win->addText ("…"); + + } } void DialogueManager::updateTopics() From af9e126487704ccf69090e7f4851e2ea8828d2f1 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 19 Jan 2013 22:53:41 +0100 Subject: [PATCH 432/916] =?UTF-8?q?Add=20unicode=20number=20for=20ellipsis?= =?UTF-8?q?=20(=E2=80=A6)=20to=20code=20range?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- files/mygui/openmw_font.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index 0383c9942..b1446fae1 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -11,6 +11,7 @@ + From 31c71c029d9bfb662b1661c0422d6e325682ff1f Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 20 Jan 2013 17:01:30 +0000 Subject: [PATCH 433/916] objects with scripts attached, that are inside containers will behave correctly when the container is moved --- apps/openmw/mwworld/worldimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ee18e5d95..46c58ecab 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -685,6 +685,7 @@ namespace MWWorld { mWorldScene->removeObjectFromScene (ptr); mLocalScripts.remove (ptr); + removeContainerScripts (ptr); } } } @@ -698,6 +699,8 @@ namespace MWWorld CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; + + removeContainerScripts(ptr); if (*currCell != newCell) { @@ -725,6 +728,8 @@ namespace MWWorld MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + addContainerScripts(copy, &newCell); + mRendering->moveObjectToCell(copy, vec, currCell); if (MWWorld::Class::get(ptr).isActor()) @@ -1333,6 +1338,7 @@ namespace MWWorld if (!script.empty()) { mLocalScripts.add(script, dropped); } + addContainerScripts(dropped, &cell); } } From 713d324eeb6713d62436454619ca2c6614d48dc7 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sun, 20 Jan 2013 19:07:33 +0100 Subject: [PATCH 434/916] - Minor code cleanup --- apps/openmw/mwrender/terrain.cpp | 2 +- apps/openmw/mwworld/cellstore.hpp | 5 ++++- apps/openmw/mwworld/esmstore.cpp | 5 ++--- components/esm/esmreader.hpp | 6 +++--- components/esm/loadland.cpp | 2 +- components/esm/loadland.hpp | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index eb5b07af4..676139cf5 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -143,7 +143,7 @@ namespace MWRender std::map indexes; initTerrainTextures(&terrainData, cellX, cellY, x * numTextures, y * numTextures, - numTextures, indexes, land->plugin); + numTextures, indexes, land->mPlugin); if (mTerrainGroup.getTerrain(terrainX, terrainY) == NULL) { diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2b25faa70..cbaf56458 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -98,7 +98,10 @@ namespace MWWorld /// A list of container references. These references do not track their mRefnumber. /// Otherwise, taking 1 of 20 instances of an object would produce multiple objects /// with the same reference. - // TODO: Check how Morrowind does this! Maybe auto-generate references on drop. + /// Unfortunately, this also means that we need a different STL container. + /// (cells use CellRefList, where refs can be located according to their refnumner, + /// which uses a map; container items do not make use of the refnumber, so we + /// can't use a map with refnumber keys.) template struct ContainerRefList { diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 38fadca9e..1666ad823 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -28,8 +28,8 @@ void ESMStore::load(ESM::ESMReader &esm) ESM::Dialogue *dialogue = 0; // Cache parent esX files by tracking their indices in the global list of - // all files/readers used by the engine. This will greaty help to accelerate - // parsing of reference IDs. + // all files/readers used by the engine. This will greaty accelerate + // refnumber mangling, as required for handling moved references. int index = ~0; const ESM::ESMReader::MasterList &masters = esm.getMasters(); std::vector *allPlugins = esm.getGlobalReaderList(); @@ -122,7 +122,6 @@ void ESMStore::load(ESM::ESMReader &esm) cout << *it << " "; cout << endl; */ - //setUp(); } void ESMStore::setUp() diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index df4c1919e..ba7d6c3e0 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -80,9 +80,9 @@ public: // terrain palette, but ESMReader does not pass a reference to the correct plugin // to the individual load() methods. This hack allows to pass this reference // indirectly to the load() method. - int idx; - void setIndex(const int index) {idx = index; mCtx.index = index;} - const int getIndex() {return idx;} + int mIdx; + void setIndex(const int index) {mIdx = index; mCtx.index = index;} + const int getIndex() {return mIdx;} void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} std::vector *getGlobalReaderList() {return mGlobalReaderList;} diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index ecc25501f..89b48c27d 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -81,7 +81,7 @@ Land::~Land() void Land::load(ESMReader &esm) { mEsm = &esm; - plugin = mEsm->getIndex(); + mPlugin = mEsm->getIndex(); // Get the grid location esm.getSubNameIs("INTV"); diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index f72d020ac..c1cce5e7e 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -23,7 +23,7 @@ struct Land int mFlags; // Only first four bits seem to be used, don't know what // they mean. int mX, mY; // Map coordinates. - int plugin; // Plugin index, used to reference the correct material palette. + int mPlugin; // Plugin index, used to reference the correct material palette. // File context. This allows the ESM reader to be 'reset' to this // location later when we are ready to load the full data set. From e1e76bde76fd441f867d20d412c9bfd2e53808aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 15:39:43 -0800 Subject: [PATCH 435/916] Combine a loop into another where it's used --- apps/openmw/mwrender/animation.cpp | 38 ++++++++++++++---------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 67be0bf0c..4884712c3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -67,34 +67,32 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { - Ogre::Bone *bone = boneiter.peekNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(NifOgre::sTextKeyExtraDataID); - if(!data.isEmpty()) - { - mTextKeys["all"] = Ogre::any_cast(data); + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty()) + continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); - mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mTextKeys["all"] = Ogre::any_cast(data); - mStartPosition = mNonAccumRoot->getPosition(); - mLastPosition = mStartPosition; - break; - } - boneiter.moveNext(); - } + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); + mNonAccumRoot = skelinst->getBone(bone->getHandle()); + + mStartPosition = mNonAccumRoot->getPosition(); + mLastPosition = mStartPosition; - if(boneiter.hasMoreElements()) - { asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { Ogre::AnimationState *state = asiter.getNext(); - Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+"@"+state->getAnimationName()); - if(!data.isEmpty()) - mTextKeys[state->getAnimationName()] = Ogre::any_cast(data); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+state->getAnimationName()); + if(!groupdata.isEmpty()) + mTextKeys[state->getAnimationName()] = Ogre::any_cast(groupdata); } + + break; } } } From 536f8104e687d04d38fcee4c1f7b9b3218d56630 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 17:24:43 -0800 Subject: [PATCH 436/916] Do not create an 'all' animation. --- apps/openmw/mwrender/animation.cpp | 4 +--- components/nifogre/ogre_nif_loader.cpp | 29 ++++++++------------------ 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4884712c3..75a441a9c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -70,11 +70,9 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Bone *bone = boneiter.getNext(); Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty()) + if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mTextKeys["all"] = Ogre::any_cast(data); - mAccumRoot = skelinst->getRootBone(); mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 372c38e0f..357866c7c 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -308,7 +308,7 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) } -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonaccum, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { if(node->recType == Nif::RC_NiTriShape) return; @@ -341,7 +341,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vectorrecType == Nif::RC_NiTextKeyExtraData) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(extractTextKeys(tk))); + textkeys = extractTextKeys(tk); + nonaccum = bone; } e = e->extra; } @@ -353,7 +354,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector(nif.getRecord(0)); std::vector ctrls; + Ogre::Bone *nonaccum = NULL; + TextKeyMap textkeys; try { - buildBones(skel, node, ctrls); + buildBones(skel, node, nonaccum, textkeys, ctrls); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() <getBoneIterator(); - while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.peekNext(); - const Ogre::Any &data = bone->getUserObjectBindings().getUserAny(sTextKeyExtraDataID); - if(!data.isEmpty()) - { - textkeys = Ogre::any_cast(data); - break; - } - boneiter.moveNext(); - } - - buildAnimation(skel, "all", ctrls, targets, 0.0f, maxtime); + Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); + bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); @@ -459,7 +449,6 @@ void loadResource(Ogre::Resource *resource) groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); } while(insiter++ != lastkeyiter); - Ogre::UserObjectBindings &bindings = boneiter.peekNext()->getUserObjectBindings(); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 8e8900e4221d015aa10f69344584f139dc00a86f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 20 Jan 2013 22:51:39 -0800 Subject: [PATCH 437/916] Use the first bone with text keys as the nonaccum root. --- components/nifogre/ogre_nif_loader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 357866c7c..890dcf7e9 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -320,8 +320,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc bone = skel->createBone(); if(parent) parent->addChild(bone); - if(!node->boneTrafo) - bone->setManuallyControlled(true); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); bone->setScale(Ogre::Vector3(node->trafo.scale)); @@ -338,7 +336,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiTextKeyExtraData) + if(e->recType == Nif::RC_NiTextKeyExtraData && !nonaccum) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); From 6905bd18ba09abc64a3a9b157d9309a36fd34d17 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 02:59:12 -0800 Subject: [PATCH 438/916] Filter out the group name from the text keys It's already in the animation name, and the text keys are animation-specific anyway. --- apps/openmw/mwmechanics/character.cpp | 10 ++-------- components/nifogre/ogre_nif_loader.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea934a284..bc065d9d6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -103,14 +103,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) // to this actor type return; } - std::string::size_type ms = mCurrentGroup.length()+2; - if(evt.length() <= ms || evt.compare(0, ms-2, mCurrentGroup) != 0 || evt.compare(ms-2, 2, ": ") != 0) - { - std::cerr<< "Event \""<first - keyiter->first, insiter->second)); + sep = insiter->second.find(':'); + if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, + insiter->second.substr(sep+2))); + else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) + groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); } while(insiter++ != lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); From e956a1cbc0e9c28aef893cedde957dc41c744f5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 03:24:52 -0800 Subject: [PATCH 439/916] Merge SpecialIdle character state into Idle --- apps/openmw/mwmechanics/character.cpp | 19 +++++++------------ apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bc065d9d6..d0cbf0477 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -36,8 +36,7 @@ static const struct { const char groupname[32]; Ogre::Vector3 accumulate; } sStateList[] = { - { CharState_SpecialIdle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle, "idle", Ogre::Vector3::ZERO }, + { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, @@ -163,8 +162,7 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_SpecialIdle || getState() == CharState_Idle || - getState() == CharState_Dead)) + if(!(getState() == CharState_Idle || getState() == CharState_Dead)) { movement = mDirection * movement.length(); } @@ -175,7 +173,9 @@ Ogre::Vector3 CharacterController::update(float duration) void CharacterController::playGroup(const std::string &groupname, int mode, int count) { - if(mAnimation && mAnimation->hasAnimation(groupname)) + if(!mAnimation || !mAnimation->hasAnimation(groupname)) + std::cerr<< "Animation "< 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; - mState = CharState_SpecialIdle; + mState = CharState_Idle; mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); @@ -207,12 +207,7 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) - { - // If setting the same state again, only reset the animation if looping - // is being turned on. - if(mLoop == loop || !(mLoop=loop)) - return; - } + return; else { mState = state; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 43ff21dfb..ec9102f9f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -14,7 +14,6 @@ namespace MWMechanics { enum CharacterState { - CharState_SpecialIdle, /* When running a PlayGroup/LoopGroup animation. */ CharState_Idle, CharState_WalkForward, From f5f3c2e62d167943cc4542e9400067c246137291 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Mon, 21 Jan 2013 20:06:08 +0000 Subject: [PATCH 440/916] enabling / disabling should not affect scripts --- apps/openmw/mwworld/worldimp.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 46c58ecab..24d139b37 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -427,8 +427,6 @@ namespace MWWorld { reference.getRefData().enable(); - addContainerScripts(reference, reference.getCell()); - if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); } @@ -459,10 +457,6 @@ namespace MWWorld { reference.getRefData().disable(); - removeContainerScripts(reference); - if(MWWorld::Class::get(reference).getScript(reference) != "") - mLocalScripts.remove(reference); - if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); } From 37fe1bd3f0f6e254501dca6c644bc2f69cac7c3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 21 Jan 2013 22:51:13 -0800 Subject: [PATCH 441/916] Handle looping in the Animation object --- apps/openmw/mwmechanics/character.cpp | 44 ++++++----------------- apps/openmw/mwmechanics/character.hpp | 1 - apps/openmw/mwrender/animation.cpp | 31 +++++++++++++++- apps/openmw/mwrender/animation.hpp | 4 ++- apps/openmw/mwrender/characterpreview.cpp | 2 +- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d0cbf0477..83326d25a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -61,8 +61,9 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(state)); } + CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false), mLoop(loop) + : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) { if(!mAnimation) return; @@ -73,13 +74,13 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim getStateInfo(mState, &mCurrentGroup, &accum); mAnimation->setAccumulation(accum); if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop"); + mAnimation->play(mCurrentGroup, "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim), mLoop(rhs.mLoop) + , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) { if(!mAnimation) return; @@ -103,32 +104,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) return; } - if(evt == "loop stop") - { - if(mAnimQueue.size() == 0) - { - if(time > 0.0f && mLoop) - mAnimation->play(mCurrentGroup, "loop start"); - } - else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start"); - } - return; - } - if(evt == "stop") { - if(mAnimQueue.size() == 0) - { - if(time > 0.0f && mLoop) - mAnimation->play(mCurrentGroup, "loop start"); - } - else if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start"); + mAnimation->play(mCurrentGroup, "loop start", false); } else if(mAnimQueue.size() > 0) { @@ -136,7 +117,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start"); + mAnimation->play(mCurrentGroup, "start", false); } } return; @@ -185,9 +166,8 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_Idle; - mLoop = false; mAnimation->setAccumulation(Ogre::Vector3::ZERO); - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start")); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) { @@ -208,11 +188,7 @@ void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) return; - else - { - mState = state; - mLoop = loop; - } + mState = state; if(!mAnimation) return; @@ -225,7 +201,7 @@ void CharacterController::setState(CharacterState state, bool loop) { mCurrentGroup = anim; mAnimation->setAccumulation(accum); - mAnimation->play(mCurrentGroup, "start"); + mAnimation->play(mCurrentGroup, "start", loop); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index ec9102f9f..53349c841 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -37,7 +37,6 @@ class CharacterController std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; - bool mLoop; protected: /* Called by the animation whenever a new text key is reached. */ diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 75a441a9c..45f7ab2e4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -173,7 +174,7 @@ float Animation::findStart(const std::string &groupname, const std::string &star } -void Animation::play(const std::string &groupname, const std::string &start) +void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { if(mAnimState) @@ -181,6 +182,7 @@ void Animation::play(const std::string &groupname, const std::string &start) mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); mCurrentKeys = &mTextKeys[groupname]; + mLooping = loop; resetPosition(findStart(groupname, start)); } @@ -209,6 +211,33 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) movement += updatePosition(time); timepassed = targetTime - time; + if(evt == "start" || evt == "loop start") + { + /* Do nothing */ + continue; + } + if(evt == "loop stop") + { + if(mLooping) + { + resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + if(mAnimState->getTimePosition() >= time) + break; + } + continue; + } + if(evt == "stop") + { + if(mLooping) + { + resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + if(mAnimState->getTimePosition() >= time) + break; + } + else if(mController) + mController->markerEvent(time, evt); + continue; + } if(mController) mController->markerEvent(time, evt); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 50ddc34d5..839813576 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,8 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + bool mLooping; + float mAnimSpeedMult; /* Updates the animation to the specified time, and returns the movement @@ -59,7 +61,7 @@ public: void setSpeedMult(float speedmult) { mAnimSpeedMult = speedmult; } - void play(const std::string &groupname, const std::string &start); + void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index cbee9c865..5a1a93311 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -144,7 +144,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->play("inventoryhandtohand", "start"); + mAnimation->play("inventoryhandtohand", "start", false); } // -------------------------------------------------------------------------------------------------- From d836b3d0ffbd9085bf06724b0aa59967982d627e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Jan 2013 00:24:57 -0800 Subject: [PATCH 442/916] Don't try to create animations if there's no text keys and nonaccum node. Such meshes apparently use NiBSAnimationNode, a Bethesda-specific extension which has animation-related info in its flags (values currently unknown). --- components/nifogre/ogre_nif_loader.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 4ae9c79f3..adc05f7e7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -414,6 +414,13 @@ void loadResource(Ogre::Resource *resource) return; } + if(!nonaccum) + { + warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ + skel->getName()+", but no text keys. Uses NiBSAnimationNode?"); + return; + } + Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); From 05f8b8c28383dd21eb60d1042a0ba353c6503830 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 22 Jan 2013 00:31:45 -0800 Subject: [PATCH 443/916] Specify the text key to reset animations to --- apps/openmw/mwrender/animation.cpp | 45 ++++++++++-------------------- apps/openmw/mwrender/animation.hpp | 6 ++-- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 45f7ab2e4..5a5761faa 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -134,14 +134,20 @@ Ogre::Vector3 Animation::updatePosition(float time) return posdiff; } -void Animation::resetPosition(float time) +void Animation::reset(const std::string &marker) { - mAnimState->setTimePosition(time); - mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->first < time) + while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; + if(mNextKey != mCurrentKeys->end()) + mAnimState->setTimePosition(mNextKey->first); + else + { + mNextKey = mCurrentKeys->begin(); + mAnimState->setTimePosition(0.0f); + } + if(mNonAccumRoot) { mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); @@ -151,29 +157,6 @@ void Animation::resetPosition(float time) } -float Animation::findStart(const std::string &groupname, const std::string &start) -{ - mNextKey = mCurrentKeys->end(); - if(mCurrentKeys->size() == 0) - return 0.0f; - - if(groupname == "all") - { - mNextKey = mCurrentKeys->begin(); - return 0.0f; - } - - std::string startmarker = groupname+": "+start; - NifOgre::TextKeyMap::const_iterator iter; - for(iter = mCurrentKeys->begin();iter != mCurrentKeys->end();iter++) - { - if(iter->second == startmarker) - return iter->first; - } - return 0.0f; -} - - void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { @@ -181,10 +164,10 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); + mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; - - resetPosition(findStart(groupname, start)); + reset(start); } catch(std::exception &e) { std::cerr<< e.what() <getAnimationName(), "loop start")); + reset("loop start"); if(mAnimState->getTimePosition() >= time) break; } @@ -230,7 +213,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - resetPosition(findStart(mAnimState->getAnimationName(), "loop start")); + reset("loop start"); if(mAnimState->getTimePosition() >= time) break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 839813576..ed9c6eb19 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,10 +38,10 @@ protected: /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Updates the animation to the specified time, without moving anything. */ - void resetPosition(float time); - float findStart(const std::string &groupname, const std::string &start); + /* Resets the animation to the time of the specified marker, without moving + * anything. If the marker is not found, it resets to the beginning. */ + void reset(const std::string &marker); void createEntityList(Ogre::SceneNode *node, const std::string &model); From 90d05858efe026d1b08252303f9c6b3534eeaa06 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 22 Jan 2013 11:50:08 +0100 Subject: [PATCH 444/916] disabling dialogue sub-views for now --- apps/opencs/view/world/tablesubview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index bb4bb76c6..f4deceb49 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -21,5 +21,6 @@ void CSVWorld::TableSubView::setEditLock (bool locked) void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) { - focusId (mTable->getUniversalId (index.row())); + /// \todo re-enable, after dialogue sub views have been fixed up +// focusId (mTable->getUniversalId (index.row())); } \ No newline at end of file From cac68c9e87fe50eb8b28644ecfcead4c3ca3f548 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 23 Jan 2013 11:48:47 +0100 Subject: [PATCH 445/916] Removed an outdated section from CMakeLists --- CMakeLists.txt | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 208d348fb..2313d2d95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,35 +67,6 @@ endif() # We probably support older versions than this. cmake_minimum_required(VERSION 2.6) -# -# Pre-built binaries being used? -# -IF(EXISTS "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd/ogre_1_7_1") - set(PREBUILT_DIR "${CMAKE_SOURCE_DIR}/prebuilt/vc100-mt-gd") - message (STATUS "OpenMW pre-built binaries found at ${PREBUILT_DIR}.") - - SET(ENV{OGRE_HOME} "${PREBUILT_DIR}/ogre_1_7_1") - - SET(ENV{BOOST_ROOT} "${PREBUILT_DIR}/boost_1_42_0") - set(Boost_USE_STATIC_LIBS ON) - set(Boost_USE_MULTITHREADED ON) - set(ENV{BOOST_INCLUDEDIR} "${BOOST_ROOT}/include") - set(ENV{BOOST_LIBRARYDIR} "${BOOST_ROOT}/lib") - - set(ENV{FREETYPE_DIR} "${PREBUILT_DIR}/freetype-2.3.5-1") - - set(USE_MPG123 OFF) - set(USE_AUDIERE ON) - set(AUDIERE_INCLUDE_DIR "${PREBUILT_DIR}/audiere-1.9.4/include") - set(AUDIERE_LIBRARY "${PREBUILT_DIR}/audiere-1.9.4/lib/audiere.lib") - - set(ENV{OPENALDIR} "${PREBUILT_DIR}/OpenAL 1.1 SDK") - - set(BULLET_ROOT "${PREBUILT_DIR}/bullet") -ELSE() - message (STATUS "OpenMW pre-built binaries not found. Using standard locations.") -ENDIF() - # source directory: libs set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) From ed9a9904b431bb27ed9725e7c83023cf5fd11bab Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 24 Jan 2013 19:39:31 +0100 Subject: [PATCH 446/916] Dialogue filter: search script variables case-insensitively --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 5d56e94b0..c1542515a 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -169,7 +169,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c int i = 0; for (; i (script->mVarNames.size()); ++i) - if (script->mVarNames[i]==name) + if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name) break; if (i>=static_cast (script->mVarNames.size())) From 19dff822f4f963fdab88d5f8f80c9b026edd6f91 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Thu, 24 Jan 2013 19:43:21 +0100 Subject: [PATCH 447/916] Dialogue: do not filter on disposition for creatures --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index c1542515a..09bb0ddc4 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -123,6 +123,11 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const { + bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); + + if (isCreature) + return true; + int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); return actorDisposition >= info.mData.mDisposition; From 6faf6f57e1c64870f8bd954679fb16352d2219f4 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Fri, 25 Jan 2013 05:19:06 +0100 Subject: [PATCH 448/916] Added settings file reader/writers for openmw.cfg and settings.cfg --- apps/launcher/CMakeLists.txt | 7 ++ apps/launcher/settings/gamesettings.cpp | 34 ++++++++ apps/launcher/settings/gamesettings.hpp | 15 ++++ apps/launcher/settings/graphicssettings.cpp | 46 +++++++++++ apps/launcher/settings/graphicssettings.hpp | 16 ++++ apps/launcher/settings/settingsbase.hpp | 88 +++++++++++++++++++++ 6 files changed, 206 insertions(+) create mode 100644 apps/launcher/settings/gamesettings.cpp create mode 100644 apps/launcher/settings/gamesettings.hpp create mode 100644 apps/launcher/settings/graphicssettings.cpp create mode 100644 apps/launcher/settings/graphicssettings.hpp create mode 100644 apps/launcher/settings/settingsbase.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 09beaf59d..2895b6345 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -9,6 +9,9 @@ set(LAUNCHER model/modelitem.cpp model/esm/esmfile.cpp + settings/gamesettings.cpp + settings/graphicssettings.cpp + utils/filedialog.cpp utils/naturalsort.cpp utils/lineedit.cpp @@ -28,6 +31,10 @@ set(LAUNCHER_HEADER model/modelitem.hpp model/esm/esmfile.hpp + settings/gamesettings.hpp + settings/graphicssettings.hpp + settings/settingsbase.hpp + utils/lineedit.hpp utils/filedialog.hpp utils/naturalsort.hpp diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp new file mode 100644 index 000000000..32f03ddbe --- /dev/null +++ b/apps/launcher/settings/gamesettings.cpp @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#include + +#include "gamesettings.hpp" + +GameSettings::GameSettings() +{ +} + +GameSettings::~GameSettings() +{ +} + +bool GameSettings::writeFile(QTextStream &stream) +{ + QMap settings = SettingsBase::getSettings(); + + QMapIterator i(settings); + while (i.hasNext()) { + i.next(); + + // Quote values with spaces + if (i.value().contains(" ")) { + stream << i.key() << "=\"" << i.value() << "\"\n"; + } else { + stream << i.key() << "=" << i.value() << "\n"; + } + + } +} diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp new file mode 100644 index 000000000..c81c67d97 --- /dev/null +++ b/apps/launcher/settings/gamesettings.hpp @@ -0,0 +1,15 @@ +#ifndef GAMESETTINGS_HPP +#define GAMESETTINGS_HPP + +#include "settingsbase.hpp" + +class GameSettings : public SettingsBase> +{ +public: + GameSettings(); + ~GameSettings(); + + bool writeFile(QTextStream &stream); +}; + +#endif // GAMESETTINGS_HPP diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp new file mode 100644 index 000000000..fd70917b5 --- /dev/null +++ b/apps/launcher/settings/graphicssettings.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +#include + +#include "graphicssettings.hpp" + +GraphicsSettings::GraphicsSettings() +{ +} + +GraphicsSettings::~GraphicsSettings() +{ +} + +bool GraphicsSettings::writeFile(QTextStream &stream) +{ + QString sectionPrefix; + QRegExp sectionRe("([^/]+)/(.+)$"); + QMap settings = SettingsBase::getSettings(); + + QMapIterator i(settings); + while (i.hasNext()) { + i.next(); + + QString prefix; + QString key; + + if (sectionRe.exactMatch(i.key())) { + prefix = sectionRe.cap(1); + key = sectionRe.cap(2); + } + + if (sectionPrefix != prefix) { + sectionPrefix = prefix; + stream << "\n[" << prefix << "]\n"; + } + + stream << key << " = " << i.value() << "\n"; + } + + return true; + +} diff --git a/apps/launcher/settings/graphicssettings.hpp b/apps/launcher/settings/graphicssettings.hpp new file mode 100644 index 000000000..8c690ebc5 --- /dev/null +++ b/apps/launcher/settings/graphicssettings.hpp @@ -0,0 +1,16 @@ +#ifndef GRAPHICSSETTINGS_HPP +#define GRAPHICSSETTINGS_HPP + +#include "settingsbase.hpp" + +class GraphicsSettings : public SettingsBase> +{ +public: + GraphicsSettings(); + ~GraphicsSettings(); + + bool writeFile(QTextStream &stream); + +}; + +#endif // GRAPHICSSETTINGS_HPP diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp new file mode 100644 index 000000000..6b8b52762 --- /dev/null +++ b/apps/launcher/settings/settingsbase.hpp @@ -0,0 +1,88 @@ +#ifndef SETTINGSBASE_HPP +#define SETTINGSBASE_HPP + +#include +#include +#include +#include + +#include + +template +class SettingsBase +{ + +public: + SettingsBase() {} + ~SettingsBase() {} + + inline QString value(const QString &key, const QString &defaultValue = QString()) + { + return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key); + } + + inline void setValue(const QString &key, const QString &value) + { + mSettings.insert(key, value); + } + + Map getSettings() {return mSettings;} + + bool readFile(QTextStream &stream) + { + mCache.clear(); + + QString sectionPrefix; + QRegExp sectionRe("^\\[([^]]+)\\]"); + QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); + + while (!stream.atEnd()) { + QString line = stream.readLine().simplified(); + + if (line.isEmpty() || line.startsWith("#")) + continue; + + if (sectionRe.exactMatch(line)) { + sectionPrefix = sectionRe.cap(1); + sectionPrefix.append("/"); + continue; + } + + if (keyRe.indexIn(line) != -1) { + + QString key = keyRe.cap(1).simplified(); + QString value = keyRe.cap(2).simplified(); + + if (!sectionPrefix.isEmpty()) + key.prepend(sectionPrefix); + + // QMap will replace the value if key exists, QMultiMap creates a new one + mCache.insert(key, value); + } + } + + if (mSettings.isEmpty()) { + mSettings = mCache; // This is the first time we read a file + return true; + } + + // Replace values from previous settings + QMapIterator i(mCache); + while (i.hasNext()) { + i.next(); + if (mSettings.contains(i.key())) + mSettings.remove(i.key()); + } + + // Merge the changed keys with those which didn't + mSettings.unite(mCache); + qDebug() << mSettings; + return true; + } + +private: + Map mSettings; + Map mCache; +}; + +#endif // SETTINGSBASE_HPP From 854eff321f3992d8da6e324577d130df0d3e1f7d Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Fri, 25 Jan 2013 17:54:05 +0100 Subject: [PATCH 449/916] - Some time ago, upstream/master did merge the submodule 'shiny' into upstream/master. This branch now does this as well. --- extern/shiny | 1 - extern/shiny/CMakeLists.txt | 75 + extern/shiny/Docs/Configurations.dox | 32 + extern/shiny/Docs/Doxyfile | 1826 ++++ extern/shiny/Docs/GettingStarted.dox | 65 + extern/shiny/Docs/Lod.dox | 49 + extern/shiny/Docs/Macros.dox | 270 + extern/shiny/Docs/Mainpage.dox | 13 + extern/shiny/Docs/Materials.dox | 128 + extern/shiny/Extra/core.h | 168 + extern/shiny/License.txt | 9 + extern/shiny/Main/Factory.cpp | 583 ++ extern/shiny/Main/Factory.hpp | 207 + extern/shiny/Main/Language.hpp | 16 + extern/shiny/Main/MaterialInstance.cpp | 220 + extern/shiny/Main/MaterialInstance.hpp | 104 + extern/shiny/Main/MaterialInstancePass.cpp | 16 + extern/shiny/Main/MaterialInstancePass.hpp | 29 + .../Main/MaterialInstanceTextureUnit.cpp | 14 + .../Main/MaterialInstanceTextureUnit.hpp | 26 + extern/shiny/Main/Platform.cpp | 94 + extern/shiny/Main/Platform.hpp | 145 + extern/shiny/Main/Preprocessor.cpp | 99 + extern/shiny/Main/Preprocessor.hpp | 69 + extern/shiny/Main/PropertyBase.cpp | 268 + extern/shiny/Main/PropertyBase.hpp | 235 + extern/shiny/Main/ScriptLoader.cpp | 401 + extern/shiny/Main/ScriptLoader.hpp | 134 + extern/shiny/Main/ShaderInstance.cpp | 707 ++ extern/shiny/Main/ShaderInstance.hpp | 71 + extern/shiny/Main/ShaderSet.cpp | 172 + extern/shiny/Main/ShaderSet.hpp | 71 + .../shiny/Platforms/Ogre/OgreGpuProgram.cpp | 70 + .../shiny/Platforms/Ogre/OgreGpuProgram.hpp | 31 + extern/shiny/Platforms/Ogre/OgreMaterial.cpp | 99 + extern/shiny/Platforms/Ogre/OgreMaterial.hpp | 38 + .../Platforms/Ogre/OgreMaterialSerializer.cpp | 67 + .../Platforms/Ogre/OgreMaterialSerializer.hpp | 29 + extern/shiny/Platforms/Ogre/OgrePass.cpp | 128 + extern/shiny/Platforms/Ogre/OgrePass.hpp | 35 + extern/shiny/Platforms/Ogre/OgrePlatform.cpp | 174 + extern/shiny/Platforms/Ogre/OgrePlatform.hpp | 72 + .../Platforms/Ogre/OgreTextureUnitState.cpp | 40 + .../Platforms/Ogre/OgreTextureUnitState.hpp | 27 + extern/shiny/Preprocessor/aq.cpp | 236 + extern/shiny/Preprocessor/cpp_re.cpp | 442 + extern/shiny/Preprocessor/cpp_re.inc | 9044 +++++++++++++++++ .../instantiate_cpp_exprgrammar.cpp | 52 + .../Preprocessor/instantiate_cpp_grammar.cpp | 56 + .../instantiate_cpp_literalgrs.cpp | 56 + .../instantiate_defined_grammar.cpp | 52 + .../instantiate_predef_macros.cpp | 52 + .../Preprocessor/instantiate_re2c_lexer.cpp | 65 + .../instantiate_re2c_lexer_str.cpp | 64 + extern/shiny/Preprocessor/token_ids.cpp | 447 + extern/shiny/Readme.txt | 33 + 56 files changed, 17725 insertions(+), 1 deletion(-) delete mode 160000 extern/shiny create mode 100644 extern/shiny/CMakeLists.txt create mode 100644 extern/shiny/Docs/Configurations.dox create mode 100644 extern/shiny/Docs/Doxyfile create mode 100644 extern/shiny/Docs/GettingStarted.dox create mode 100644 extern/shiny/Docs/Lod.dox create mode 100644 extern/shiny/Docs/Macros.dox create mode 100644 extern/shiny/Docs/Mainpage.dox create mode 100644 extern/shiny/Docs/Materials.dox create mode 100644 extern/shiny/Extra/core.h create mode 100644 extern/shiny/License.txt create mode 100644 extern/shiny/Main/Factory.cpp create mode 100644 extern/shiny/Main/Factory.hpp create mode 100644 extern/shiny/Main/Language.hpp create mode 100644 extern/shiny/Main/MaterialInstance.cpp create mode 100644 extern/shiny/Main/MaterialInstance.hpp create mode 100644 extern/shiny/Main/MaterialInstancePass.cpp create mode 100644 extern/shiny/Main/MaterialInstancePass.hpp create mode 100644 extern/shiny/Main/MaterialInstanceTextureUnit.cpp create mode 100644 extern/shiny/Main/MaterialInstanceTextureUnit.hpp create mode 100644 extern/shiny/Main/Platform.cpp create mode 100644 extern/shiny/Main/Platform.hpp create mode 100644 extern/shiny/Main/Preprocessor.cpp create mode 100644 extern/shiny/Main/Preprocessor.hpp create mode 100644 extern/shiny/Main/PropertyBase.cpp create mode 100644 extern/shiny/Main/PropertyBase.hpp create mode 100644 extern/shiny/Main/ScriptLoader.cpp create mode 100644 extern/shiny/Main/ScriptLoader.hpp create mode 100644 extern/shiny/Main/ShaderInstance.cpp create mode 100644 extern/shiny/Main/ShaderInstance.hpp create mode 100644 extern/shiny/Main/ShaderSet.cpp create mode 100644 extern/shiny/Main/ShaderSet.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgreMaterial.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgreMaterial.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgrePass.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgrePass.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgrePlatform.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgrePlatform.hpp create mode 100644 extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp create mode 100644 extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp create mode 100644 extern/shiny/Preprocessor/aq.cpp create mode 100644 extern/shiny/Preprocessor/cpp_re.cpp create mode 100644 extern/shiny/Preprocessor/cpp_re.inc create mode 100644 extern/shiny/Preprocessor/instantiate_cpp_exprgrammar.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_cpp_grammar.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_cpp_literalgrs.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_defined_grammar.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_predef_macros.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_re2c_lexer.cpp create mode 100644 extern/shiny/Preprocessor/instantiate_re2c_lexer_str.cpp create mode 100644 extern/shiny/Preprocessor/token_ids.cpp create mode 100644 extern/shiny/Readme.txt diff --git a/extern/shiny b/extern/shiny deleted file mode 160000 index 4750676ac..000000000 --- a/extern/shiny +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4750676ac46a7aaa86bca53dc68c5a1ba11f3bc1 diff --git a/extern/shiny/CMakeLists.txt b/extern/shiny/CMakeLists.txt new file mode 100644 index 000000000..603336413 --- /dev/null +++ b/extern/shiny/CMakeLists.txt @@ -0,0 +1,75 @@ +cmake_minimum_required(VERSION 2.8) + +# This is NOT intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project. +# Make sure to link against Ogre and boost::filesystem. + +option(SHINY_BUILD_OGRE_PLATFORM "build the Ogre platform" ON) + +set(SHINY_LIBRARY "shiny") +set(SHINY_OGREPLATFORM_LIBRARY "shiny.OgrePlatform") + +# Sources +file(GLOB SOURCE_FILES Main/*.cpp ) + +set(SOURCE_FILES + Main/Factory.cpp + Main/MaterialInstance.cpp + Main/MaterialInstancePass.cpp + Main/MaterialInstanceTextureUnit.cpp + Main/Platform.cpp + Main/Preprocessor.cpp + Main/PropertyBase.cpp + Main/ScriptLoader.cpp + Main/ShaderInstance.cpp + Main/ShaderSet.cpp +) + +# In Debug mode, write the shader sources to the current directory +if (DEFINED CMAKE_BUILD_TYPE) + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions(-DSHINY_WRITE_SHADER_DEBUG) + endif() +endif() + +if (DEFINED SHINY_USE_WAVE_SYSTEM_INSTALL) + # use system install +else() + list(APPEND SOURCE_FILES + Preprocessor/aq.cpp + Preprocessor/cpp_re.cpp + Preprocessor/instantiate_cpp_literalgrs.cpp + Preprocessor/instantiate_cpp_exprgrammar.cpp + Preprocessor/instantiate_cpp_grammar.cpp + Preprocessor/instantiate_defined_grammar.cpp + Preprocessor/instantiate_predef_macros.cpp + Preprocessor/instantiate_re2c_lexer.cpp + Preprocessor/instantiate_re2c_lexer_str.cpp + Preprocessor/token_ids.cpp + ) + + # Don't use thread-safe boost::wave. Results in a huge speed-up for the preprocessor. + add_definitions(-DBOOST_WAVE_SUPPORT_THREADING=0) +endif() + +set(OGRE_PLATFORM_SOURCE_FILES + Platforms/Ogre/OgreGpuProgram.cpp + Platforms/Ogre/OgreMaterial.cpp + Platforms/Ogre/OgreMaterialSerializer.cpp + Platforms/Ogre/OgrePass.cpp + Platforms/Ogre/OgrePlatform.cpp + Platforms/Ogre/OgreTextureUnitState.cpp +) + +file(GLOB OGRE_PLATFORM_SOURCE_FILES Platforms/Ogre/*.cpp) + +add_library(${SHINY_LIBRARY} STATIC ${SOURCE_FILES}) + +if (SHINY_BUILD_OGRE_PLATFORM) + add_library(${SHINY_OGREPLATFORM_LIBRARY} STATIC ${OGRE_PLATFORM_SOURCE_FILES}) +endif() + + +link_directories(${CMAKE_CURRENT_BINARY_DIR}) + +set(SHINY_LIBRARY ${SHINY_LIBRARY} PARENT_SCOPE) +set(SHINY_OGREPLATFORM_LIBRARY ${SHINY_OGREPLATFORM_LIBRARY} PARENT_SCOPE) diff --git a/extern/shiny/Docs/Configurations.dox b/extern/shiny/Docs/Configurations.dox new file mode 100644 index 000000000..affd91423 --- /dev/null +++ b/extern/shiny/Docs/Configurations.dox @@ -0,0 +1,32 @@ +/*! + + \page configurations Configurations + + A common task in shader development is to provide a different set of simpler shaders for all your materials. Some examples: + - When rendering cubic or planar reflection maps in real-time, you will want to disable shadows. + - For an in-game minimap render target, you don't want to have fog. + + For this task, the library provides a \a Configuration concept. + + A Configuration is a set of properties that can override global settings, as long as this Configuration is active. + + Here's an example. Say you have a global setting with the name 'shadows' that controls if your materials receive shadows. + + Now, lets create a configuration for our reflection render targets that disables shadows for all materials. Paste the following in a new file with the extension '.configuration': + + \code + configuration reflection_targets + { + shadows false + } + \endcode + + \note You may also create configurations using sh::Factory::registerConfiguration. + + The active Configuration is controlled by the active material scheme in Ogre. So, in order to use the configuration "reflection_targets" for your reflection renders, simply call + \code + viewport->setMaterialScheme ("reflection_targets"); + \endcode + on the Ogre viewport of your reflection render! + +*/ diff --git a/extern/shiny/Docs/Doxyfile b/extern/shiny/Docs/Doxyfile new file mode 100644 index 000000000..3564c45f6 --- /dev/null +++ b/extern/shiny/Docs/Doxyfile @@ -0,0 +1,1826 @@ +# Doxyfile 1.8.1.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = shiny + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = /home/scrawl/sh_doxy/generated + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/extern/shiny/Docs/GettingStarted.dox b/extern/shiny/Docs/GettingStarted.dox new file mode 100644 index 000000000..b9cf58e23 --- /dev/null +++ b/extern/shiny/Docs/GettingStarted.dox @@ -0,0 +1,65 @@ +/*! + \page getting-started Getting started + + \section download Download the source + + \code + git clone git@github.com:scrawl/shiny.git + \endcode + + \section building Build the source + + The source files you want to build are: + - Main/*.cpp + - Preprocessor/*.cpp (unless you are using the system install of boost::wave, more below) + - Platforms/Ogre/*.cpp + + You can either build the sources as a static library, or simply add the sources to the source tree of your project. + + If you use CMake, you might find the included CMakeLists.txt useful. It builds static libraries with the names "shiny" and "shiny.OgrePlatform". + + \note The CMakeLists.txt is not intended as a stand-alone build system! Instead, you should include this from the main CMakeLists of your project. + + Make sure to link against OGRE and the boost filesystem library. + + If your boost version is older than 1.49, you must set the SHINY_USE_WAVE_SYSTEM_INSTALL variable and additionally link against the boost wave library. + + \code + set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE") + \endcode + + \section code Basic initialisation code + + Add the following code to your application: + + \code{cpp} + + #include + #include + + .... + + sh::OgrePlatform* platform = new sh::OgrePlatform( + "General", // OGRE Resource group to use for creating materials. + myApplication.getDataPath() + "/" + "materials" // Path to look for materials and shaders. NOTE: This does NOT use the Ogre resource system, so you have to specify an absolute path. + ); + + sh::Factory* factory = new sh::Factory(platform); + + // Set a language. Valid options: CG, HLSL, GLSL + factory->setCurrentLanguage(sh::Language_GLSL); + + factory->loadAllFiles(); + + .... + your application runs here + .... + + // don't forget to delete on exit + delete factory; + + \endcode + + That's it! Now you can start defining materials. Refer to the page \ref defining-materials-shaders . + +*/ diff --git a/extern/shiny/Docs/Lod.dox b/extern/shiny/Docs/Lod.dox new file mode 100644 index 000000000..37d004638 --- /dev/null +++ b/extern/shiny/Docs/Lod.dox @@ -0,0 +1,49 @@ +/*! + + \page lod Material LOD + + \section howitworks How it works + + When Ogre requests a technique for a specific LOD index, the Factory selects the appropriate LOD configuration which then temporarily overrides the global settings in the shaders. We can use this to disable shader features one by one at a lower LOD, resulting in simpler and faster techniques for distant objects. + + \section howtouseit How to use it + + - Create a file with the extension '.lod'. There you can specify shader features to disable at a specific LOD level. Higher LOD index refers to a lower LOD. Example contents: + + \code + lod_configuration 1 + { + specular_mapping false + } + + lod_configuration 2 + { + specular_mapping false + normal_mapping false + } + + lod_configuration 3 + { + terrain_composite_map true + specular_mapping false + normal_mapping false + } + \endcode + + \note You can also add LOD configurations by calling \a sh::Factory::registerLodConfiguration. + + \note Do not use an index of 0. LOD 0 refers to the highest LOD, and you will never want to disable features at the highest LOD level. + + + - In your materials, specify the distances at which a lower LOD kicks in. Note that the actual distance might also be affected by the viewport and current entity LOD bias. In this example, the first LOD level (lod index 1) would normally be applied at a distance of 100 units, the next after 300, and the last after 1000 units. + + \code + material sample_material + { + lod_values 100 300 1000 + + ... your passes, texture units etc ... + } + \endcode + +*/ diff --git a/extern/shiny/Docs/Macros.dox b/extern/shiny/Docs/Macros.dox new file mode 100644 index 000000000..0578c447f --- /dev/null +++ b/extern/shiny/Docs/Macros.dox @@ -0,0 +1,270 @@ +/*! + \page macros Shader Macros + + \tableofcontents + + \section Shader Language + + These macros are automatically defined, depending on the shader language that has been set by the application using sh::Factory::setCurrentLanguage. + + - SH_GLSL + - SH_HLSL + - SH_CG + + Example: + + \code + #if SH_GLSL == 1 + // glsl porting code + #endif + + #if SH_CG == 1 || SH_HLSL == 1 + // cg / hlsl porting code (similiar syntax) + #endif + \endcode + + \note It is encouraged to use the shipped porting header (extra/core.h) by #include-ing it in your shaders. If you do that, you should not have to use the above macros directly. + + \section vertex-fragment Vertex / fragment shader + + These macros are automatically defined, depending on the type of shader that is currently being compiled. + + - SH_VERTEX_SHADER + - SH_FRAGMENT_SHADER + + If you use the same source file for both vertex and fragment shader, then it is advised to use these macros for blending out the unused source. This will reduce your compile time. + + \section passthrough Vertex -> Fragment passthrough + + In shader development, a common task is to pass variables from the vertex to the fragment shader. This is no problem if you have a deterministic shader source (i.e. no #ifdefs). + + However, as soon as you begin to have lots of permutations of the same shader source, a problem arises. All current GPUs have a limit of 8 vertex to fragment passthroughs (with 4 components each, for example a float4). + + A common optimization is to put several individual float values together in a float4 (so-called "Packing"). But if your shader has lots of permutations and the passthrough elements you actually need are not known beforehand, it can be very tedious to pack manually. With the following macros, packing can become easier. + + \subsection shAllocatePassthrough shAllocatePassthrough + + Usage: \@shAllocatePassthrough(num_components, name) + + Example: + \code + #if FRAGMENT_NEED_DEPTH + @shAllocatePassthrough(1, depth) + #endif + \endcode + + This is the first thing you should do before using any of the macros below. + + \subsection shPassthroughVertexOutputs shPassthroughVertexOutputs + + Usage: \@shPassthroughVertexOutputs + + Use this in the inputs/outputs section of your vertex shader, in order to declare all the outputs that are needed for packing the variables that you want passed to the fragment. + + \subsection shPassthroughFragmentInputs shPassthroughFragmentInputs + + Usage: \@shPassthroughFragmentInputs + + Use this in the inputs/outputs section of your fragment shader, in order to declare all the inputs that are needed for receiving the variables that you want passed to the fragment. + + \subsection shPassthroughAssign shPassthroughAssign + + Usage: \@shPassthroughAssign(name, value) + + Use this in the vertex shader for assigning a value to the variable you want passed to the fragment. + + Example: + \code + #if FRAGMENT_NEED_DEPTH + @shPassthroughAssign(depth, shOutputPosition.z); + #endif + + \endcode + + \subsection shPassthroughReceive shPassthroughReceive + + Usage: \@shPassthroughReceive(name) + + Use this in the fragment shader to receive the passed value. + + Example: + + \code + #if FRAGMENT_NEED_DEPTH + float depth = @shPassthroughReceive(depth); + #endif + \endcode + + \section texUnits Texture units + + \subsection shUseSampler shUseSampler + + Usage: \@shUseSampler(samplerName) + + Requests the texture unit with name \a samplerName to be available for use in this pass. + + Why is this necessary? If you have a derived material that does not use all of the texture units that its parent defines (for example, if an optional asset such as a normal map is not available), there would be no way to know which texture units are actually needed and which can be skipped in the creation process (those that are never referenced in the shader). + + \section properties Property retrieval / binding + + \subsection shUniformProperty shUniformProperty + + Usage: \@shUniformProperty<4f|3f|2f|1f|int> (uniformName, property) + + Binds the value of \a property (from the shader_properties of the pass this shader belongs to) to the uniform with name \a uniformName. + + The following variants are available, depending on the type of your uniform variable: + - \@shUniformProperty4f + - \@shUniformProperty3f + - \@shUniformProperty2f + - \@shUniformProperty1f + - \@shUniformPropertyInt + + Example: \@shUniformProperty1f (uFresnelScale, fresnelScale) + + \subsection shPropertyBool shPropertyBool + + Retrieve a boolean property of the pass that this shader belongs to, gets replaced with either 0 or 1. + + Usage: \@shPropertyBool(propertyName) + + Example: + \code + #if @shPropertyBool(has_normal_map) + ... + #endif + \endcode + + \subsection shPropertyNotBool shPropertyNotBool + + Same as shPropertyBool, but inverts the result (i.e. when shPropertyBool would return 0, this returns 1 and vice versa) + + \subsection shPropertyString shPropertyString + + Retrieve a string property of the pass that this shader belongs to + + Usage: \@shPropertyString(propertyName) + + \subsection shPropertyEqual shPropertyEqual + + Check if the value of a property equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers. + + Usage: \@shPropertyEqual(propertyName, value) + + Example: + \code + #if @shPropertyEqual(lighting_mode, phong) + ... + #endif + \endcode + + \section globalSettings Global settings + + \subsection shGlobalSettingBool shGlobalSettingBool + + Retrieves the boolean value of a specific global setting, gets replaced with either 0 or 1. The value can be set using sh::Factory::setGlobalSetting. + + Usage: \@shGlobalSettingBool(settingName) + + \subsection shGlobalSettingEqual shGlobalSettingEqual + + Check if the value of a global setting equals a specific value, gets replaced with either 0 or 1. This is useful because the preprocessor cannot compare strings, only numbers. + + Usage: \@shGlobalSettingEqual(settingName, value) + + \subsection shGlobalSettingString shGlobalSettingString + + Gets replaced with the current value of a given global setting. The value can be set using sh::Factory::setGlobalSetting. + + Usage: \@shGlobalSettingString(settingName) + + \section sharedParams Shared parameters + + \subsection shSharedParameter shSharedParameter + + Allows you to bind a custom value to a uniform parameter. + + Usage: \@shSharedParameter(sharedParameterName) + + Example: \@shSharedParameter(pssmSplitPoints) - now the uniform parameter 'pssmSplitPoints' can be altered in all shaders that use it by executing sh::Factory::setSharedParameter("pssmSplitPoints", value) + + \note You may use the same shared parameter in as many shaders as you want. But don't forget to add the \@shSharedParameter macro to every shader that uses this shared parameter. + + \section autoconstants Auto constants + + \subsection shAutoConstant shAutoConstant + + Usage: \@shAutoConstant(uniformName, autoConstantName, [extraData]) + + Example: \@shAutoConstant(uModelViewMatrix, worldviewproj_matrix) + + Example: \@shAutoConstant(uLightPosition4, light_position, 4) + + Binds auto constant with name \a autoConstantName to the uniform \a uniformName. Optionally, you may specify extra data (for example the light index), as required by some auto constants. + + The auto constant names are the same as Ogre's. Read the section "3.1.9 Using Vertex/Geometry/Fragment Programs in a Pass" of the Ogre manual for a list of all auto constant names. + + \section misc Misc + + \subsection shForeach shForeach + + Usage: \@shForeach(n) + + Repeats the content of this foreach block \a n times. The end of the block is marked via \@shEndForeach, and the current iteration number can be retrieved via \@shIterator. + + \note Nested foreach blocks are currently \a not supported. + + \note For technical reasons, you can only use constant numbers, properties (\@shPropertyString) or global settings (\@shGlobalSettingString) as \a n parameter. + + Example: + + \code + @shForeach(3) + this is iteration number @shIterator + @shEndForeach + + Gets replaced with: + + this is iteration number 0 + this is iteration number 1 + this is iteration number 2 + \endcode + + Optionally, you can pass a constant offset to \@shIterator. Example: + + \code + @shForeach(3) + this is iteration number @shIterator(7) + @shEndForeach + + Gets replaced with: + + this is iteration number 7 + this is iteration number 8 + this is iteration number 9 + \endcode + + \subsection shCounter shCounter + + Gets replaced after the preprocessing step with the number that equals the n-th occurence of counters of the same ID. + + Usage: \@shCounter(ID) + + Example: + \code + @shCounter(0) + @shCounter(0) + @shCounter(1) + @shCounter(0) + \endcode + + Gets replaced with: + + \code + 0 + 1 + 0 + 2 + \endcode + +*/ diff --git a/extern/shiny/Docs/Mainpage.dox b/extern/shiny/Docs/Mainpage.dox new file mode 100644 index 000000000..fb8f596dc --- /dev/null +++ b/extern/shiny/Docs/Mainpage.dox @@ -0,0 +1,13 @@ +/*! + + \mainpage + + - \ref getting-started + - \ref defining-materials-shaders + - \ref macros + - \ref configurations + - \ref lod + + - sh::Factory - the main interface class + +*/ diff --git a/extern/shiny/Docs/Materials.dox b/extern/shiny/Docs/Materials.dox new file mode 100644 index 000000000..2dae60560 --- /dev/null +++ b/extern/shiny/Docs/Materials.dox @@ -0,0 +1,128 @@ +/*! + + \page defining-materials-shaders Defining materials and shaders + + \section first-material Your first material + + Create a file called "myFirstMaterial.mat" and place it in the path you have used in your initialisation code (see \ref getting-started). Paste the following: + + \code + + material my_first_material + { + diffuse 1.0 1.0 1.0 1.0 + specular 0.4 0.4 0.4 32 + ambient 1.0 1.0 1.0 + emissive 0.0 0.0 0.0 + diffuseMap black.png + + pass + { + diffuse $diffuse + specular $specular + ambient $ambient + emissive $emissive + + texture_unit diffuseMap + { + texture $diffuseMap + create_in_ffp true // use this texture unit for fixed function pipeline + } + } + } + + material material1 + { + parent my_first_material + diffuseMap texture1.png + } + + material material2 + { + parent my_first_material + diffuseMap texture2.png + } + + \endcode + + \section first-shader The first shader + + Change the 'pass' section to include some shaders: + + \code + pass + { + vertex_program my_first_shader_vertex + fragment_program my_first_shader_fragment + ... + } + \endcode + + \note This does \a not refer to a single shader with a fixed source code, but in fact will automatically create a new \a instance of this shader (if necessary), which can have its own uniform variables, compile-time macros and much more! + + Next, we're going to define our shaders. Paste this in a new file called 'myfirstshader.shaderset' + + \code + shader_set my_first_shader_vertex + { + source example.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 + } + + shader_set my_first_shader_fragment + { + source example.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 + } + \endcode + + Some notes: + - There is no entry_point property because the entry point is always \a main. + - Both profiles_cg and profiles_hlsl are a list of shader profiles. The first profile that is supported is automatically picked. GLSL does not have shader profiles. + + Now, let's get into writing our shader! As you can guess from above, the filename should be 'example.shader' + + \code + #include "core.h" + + #ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shInput(float2, uv0) + shOutput(float2, UV) + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + } + + #else + + SH_BEGIN_PROGRAM + // NOTE: It is important that the sampler name here (diffuseMap) matches + // the name of the texture unit in the material. This is necessary because the system + // skips texture units that are never "referenced" in the shader. This can be the case + // when your base material has optional assets (for example a normal map) that are not + // used by some derived materials. + shSampler2D(diffuseMap) + shInput(float2, UV) + SH_START_PROGRAM + { + shOutputColour(0) = shSample(diffuseMap, UV); + } + + #endif + + \endcode + + There you have it! This shader will compile in several languages thanks to the porting defines in "core.h". If you need more defines, feel free to add them and don't forget to send them to me! + + For a full list of macros available when writing your shaders, refer to the page \ref macros + + In the future, some more in-depth shader examples might follow. +*/ diff --git a/extern/shiny/Extra/core.h b/extern/shiny/Extra/core.h new file mode 100644 index 000000000..cba716777 --- /dev/null +++ b/extern/shiny/Extra/core.h @@ -0,0 +1,168 @@ +#if SH_HLSL == 1 || SH_CG == 1 + + #define shTexture2D sampler2D + #define shSample(tex, coord) tex2D(tex, coord) + #define shCubicSample(tex, coord) texCUBE(tex, coord) + #define shLerp(a, b, t) lerp(a, b, t) + #define shSaturate(a) saturate(a) + + #define shSampler2D(name) , uniform sampler2D name : register(s@shCounter(0)) @shUseSampler(name) + + #define shSamplerCube(name) , uniform samplerCUBE name : register(s@shCounter(0)) @shUseSampler(name) + + #define shMatrixMult(m, v) mul(m, v) + + #define shUniform(type, name) , uniform type name + + #define shTangentInput(type) , in type tangent : TANGENT + #define shVertexInput(type, name) , in type name : TEXCOORD@shCounter(1) + #define shInput(type, name) , in type name : TEXCOORD@shCounter(1) + #define shOutput(type, name) , out type name : TEXCOORD@shCounter(2) + + #define shNormalInput(type) , in type normal : NORMAL + + #define shColourInput(type) , in type colour : COLOR + + #ifdef SH_VERTEX_SHADER + + #define shOutputPosition oPosition + #define shInputPosition iPosition + + + #define SH_BEGIN_PROGRAM \ + void main( \ + float4 iPosition : POSITION \ + , out float4 oPosition : POSITION + + #define SH_START_PROGRAM \ + ) \ + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shOutputColour(num) oColor##num + + #define shDeclareMrtOutput(num) , out float4 oColor##num : COLOR##num + + #define SH_BEGIN_PROGRAM \ + void main( \ + out float4 oColor0 : COLOR + + #define SH_START_PROGRAM \ + ) \ + + #endif + +#endif + +#if SH_GLSL == 1 + + @version 120 + + #define float2 vec2 + #define float3 vec3 + #define float4 vec4 + #define int2 ivec2 + #define int3 ivec3 + #define int4 ivec4 + #define shTexture2D sampler2D + #define shSample(tex, coord) texture2D(tex, coord) + #define shCubicSample(tex, coord) textureCube(tex, coord) + #define shLerp(a, b, t) mix(a, b, t) + #define shSaturate(a) clamp(a, 0.0, 1.0) + + #define shUniform(type, name) uniform type name; + + #define shSampler2D(name) uniform sampler2D name; @shUseSampler(name) + + #define shSamplerCube(name) uniform samplerCube name; @shUseSampler(name) + + #define shMatrixMult(m, v) (m * v) + + #define shOutputPosition gl_Position + + #define float4x4 mat4 + #define float3x3 mat3 + + // GLSL 1.3 + #if 0 + + // automatically recognized by ogre when the input name equals this + #define shInputPosition vertex + + #define shOutputColour(num) oColor##num + + #define shTangentInput(type) in type tangent; + #define shVertexInput(type, name) in type name; + #define shInput(type, name) in type name; + #define shOutput(type, name) out type name; + + // automatically recognized by ogre when the input name equals this + #define shNormalInput(type) in type normal; + #define shColourInput(type) in type colour; + + #ifdef SH_VERTEX_SHADER + + #define SH_BEGIN_PROGRAM \ + in float4 vertex; + #define SH_START_PROGRAM \ + void main(void) + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shDeclareMrtOutput(num) out vec4 oColor##num; + + #define SH_BEGIN_PROGRAM \ + out float4 oColor0; + #define SH_START_PROGRAM \ + void main(void) + + + #endif + + #endif + + // GLSL 1.2 + + #if 1 + + // automatically recognized by ogre when the input name equals this + #define shInputPosition vertex + + #define shOutputColour(num) gl_FragData[num] + + #define shTangentInput(type) attribute type tangent; + #define shVertexInput(type, name) attribute type name; + #define shInput(type, name) varying type name; + #define shOutput(type, name) varying type name; + + // automatically recognized by ogre when the input name equals this + #define shNormalInput(type) attribute type normal; + #define shColourInput(type) attribute type colour; + + #ifdef SH_VERTEX_SHADER + + #define SH_BEGIN_PROGRAM \ + attribute vec4 vertex; + #define SH_START_PROGRAM \ + void main(void) + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shDeclareMrtOutput(num) + + #define SH_BEGIN_PROGRAM + + #define SH_START_PROGRAM \ + void main(void) + + + #endif + + #endif +#endif diff --git a/extern/shiny/License.txt b/extern/shiny/License.txt new file mode 100644 index 000000000..d89bcf3ad --- /dev/null +++ b/extern/shiny/License.txt @@ -0,0 +1,9 @@ +Copyright (c) 2012 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp new file mode 100644 index 000000000..678ee25c9 --- /dev/null +++ b/extern/shiny/Main/Factory.cpp @@ -0,0 +1,583 @@ +#include "Factory.hpp" + +#include +#include + +#include +#include +#include + +#include "Platform.hpp" +#include "ScriptLoader.hpp" +#include "ShaderSet.hpp" +#include "MaterialInstanceTextureUnit.hpp" + +namespace sh +{ + Factory* Factory::sThis = 0; + + Factory& Factory::getInstance() + { + assert (sThis); + return *sThis; + } + + Factory* Factory::getInstancePtr() + { + return sThis; + } + + Factory::Factory (Platform* platform) + : mPlatform(platform) + , mShadersEnabled(true) + , mShaderDebugOutputEnabled(false) + , mCurrentLanguage(Language_None) + , mListener(NULL) + , mCurrentConfiguration(NULL) + , mCurrentLodConfiguration(NULL) + , mReadMicrocodeCache(false) + , mWriteMicrocodeCache(false) + , mReadSourceCache(false) + , mWriteSourceCache(false) + { + assert (!sThis); + sThis = this; + + mPlatform->setFactory(this); + } + + void Factory::loadAllFiles() + { + assert(mCurrentLanguage != Language_None); + + bool anyShaderDirty = false; + + if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt")) + { + std::ifstream file; + file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); + + std::string line; + while (getline(file, line)) + { + std::string sourceFile = line; + + if (!getline(file, line)) + assert(0); + + int modified = boost::lexical_cast(line); + + mShadersLastModified[sourceFile] = modified; + } + } + + // load configurations + { + ScriptLoader shaderSetLoader(".configuration"); + ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); + std::map nodes = shaderSetLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "configuration")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .configuration" << std::endl; + break; + } + + PropertySetGet newConfiguration; + newConfiguration.setParent(&mGlobalSettings); + + std::vector props = it->second->getChildren(); + for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) + { + std::string name = (*propIt)->getName(); + std::string val = (*propIt)->getValue(); + + newConfiguration.setProperty (name, makeProperty(val)); + } + + mConfigurations[it->first] = newConfiguration; + } + } + + // load lod configurations + { + ScriptLoader lodLoader(".lod"); + ScriptLoader::loadAllFiles (&lodLoader, mPlatform->getBasePath()); + std::map nodes = lodLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "lod_configuration")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .lod" << std::endl; + break; + } + + if (it->first == "0") + { + throw std::runtime_error("lod level 0 (max lod) can't have a configuration"); + } + + PropertySetGet newLod; + + std::vector props = it->second->getChildren(); + for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) + { + std::string name = (*propIt)->getName(); + std::string val = (*propIt)->getValue(); + + newLod.setProperty (name, makeProperty(val)); + } + + mLodConfigurations[boost::lexical_cast(it->first)] = newLod; + } + } + + // load shader sets + { + ScriptLoader shaderSetLoader(".shaderset"); + ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath()); + std::map nodes = shaderSetLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "shader_set")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl; + break; + } + + if (!it->second->findChild("profiles_cg")) + throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\""); + if (!it->second->findChild("profiles_hlsl")) + throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\""); + if (!it->second->findChild("source")) + throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\""); + if (!it->second->findChild("type")) + throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\""); + + std::vector profiles_cg; + boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" ")); + std::string cg_profile; + for (std::vector::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2) + { + if (mPlatform->isProfileSupported(*it2)) + { + cg_profile = *it2; + break; + } + } + + std::vector profiles_hlsl; + boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" ")); + std::string hlsl_profile; + for (std::vector::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2) + { + if (mPlatform->isProfileSupported(*it2)) + { + hlsl_profile = *it2; + break; + } + } + + std::string sourceFile = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); + + ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile, + sourceFile, + mPlatform->getBasePath(), + it->first, + &mGlobalSettings); + + int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceFile)); + if (mShadersLastModified.find(sourceFile) != mShadersLastModified.end() + && mShadersLastModified[sourceFile] != lastModified) + { + newSet.markDirty (); + anyShaderDirty = true; + } + + mShadersLastModified[sourceFile] = lastModified; + + mShaderSets.insert(std::make_pair(it->first, newSet)); + } + } + + // load materials + { + ScriptLoader materialLoader(".mat"); + ScriptLoader::loadAllFiles (&materialLoader, mPlatform->getBasePath()); + + std::map nodes = materialLoader.getAllConfigScripts(); + for (std::map ::const_iterator it = nodes.begin(); + it != nodes.end(); ++it) + { + if (!(it->second->getName() == "material")) + { + std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .mat" << std::endl; + break; + } + + MaterialInstance newInstance(it->first, this); + newInstance.create(mPlatform); + if (!mShadersEnabled) + newInstance.setShadersEnabled (false); + + newInstance.setSourceFile (it->second->m_fileName); + + std::vector props = it->second->getChildren(); + for (std::vector::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt) + { + std::string name = (*propIt)->getName(); + + std::string val = (*propIt)->getValue(); + + if (name == "pass") + { + MaterialInstancePass* newPass = newInstance.createPass(); + std::vector props2 = (*propIt)->getChildren(); + for (std::vector::const_iterator propIt2 = props2.begin(); propIt2 != props2.end(); ++propIt2) + { + std::string name2 = (*propIt2)->getName(); + std::string val2 = (*propIt2)->getValue(); + + if (name2 == "shader_properties") + { + std::vector shaderProps = (*propIt2)->getChildren(); + for (std::vector::const_iterator shaderPropIt = shaderProps.begin(); shaderPropIt != shaderProps.end(); ++shaderPropIt) + { + std::string val = (*shaderPropIt)->getValue(); + newPass->mShaderProperties.setProperty((*shaderPropIt)->getName(), makeProperty(val)); + } + } + else if (name2 == "texture_unit") + { + MaterialInstanceTextureUnit* newTex = newPass->createTextureUnit(val2); + std::vector texProps = (*propIt2)->getChildren(); + for (std::vector::const_iterator texPropIt = texProps.begin(); texPropIt != texProps.end(); ++texPropIt) + { + std::string val = (*texPropIt)->getValue(); + newTex->setProperty((*texPropIt)->getName(), makeProperty(val)); + } + } + else + newPass->setProperty((*propIt2)->getName(), makeProperty(val2)); + } + } + else if (name == "parent") + newInstance.setParentInstance(val); + else + newInstance.setProperty((*propIt)->getName(), makeProperty(val)); + } + + if (newInstance.hasProperty("create_configuration")) + { + std::string config = retrieveValue(newInstance.getProperty("create_configuration"), NULL).get(); + newInstance.createForConfiguration (config, 0); + } + + mMaterials.insert (std::make_pair(it->first, newInstance)); + } + + // now that all materials are loaded, replace the parent names with the actual pointers to parent + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + std::string parent = it->second.getParentInstance(); + if (parent != "") + { + if (mMaterials.find (it->second.getParentInstance()) == mMaterials.end()) + throw std::runtime_error ("Unable to find parent for material instance \"" + it->first + "\""); + it->second.setParent(&mMaterials.find(parent)->second); + } + } + } + + if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !anyShaderDirty) + { + std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; + if (boost::filesystem::exists(file)) + { + mPlatform->deserializeShaders (file); + } + } + } + + Factory::~Factory () + { + if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache) + { + std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; + mPlatform->serializeShaders (file); + } + + if (mReadSourceCache) + { + // save the last modified time of shader sources + std::ofstream file; + file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); + + for (LastModifiedMap::const_iterator it = mShadersLastModified.begin(); it != mShadersLastModified.end(); ++it) + { + file << it->first << "\n" << it->second << std::endl; + } + + file.close(); + } + + delete mPlatform; + sThis = 0; + } + + MaterialInstance* Factory::searchInstance (const std::string& name) + { + if (mMaterials.find(name) != mMaterials.end()) + return &mMaterials.find(name)->second; + + return NULL; + } + + MaterialInstance* Factory::findInstance (const std::string& name) + { + assert (mMaterials.find(name) != mMaterials.end()); + return &mMaterials.find(name)->second; + } + + MaterialInstance* Factory::requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex) + { + MaterialInstance* m = searchInstance (name); + + if (configuration != "Default" && mConfigurations.find(configuration) == mConfigurations.end()) + return NULL; + + if (m) + { + // make sure all lod techniques below (higher lod) exist + int i = lodIndex; + while (i>0) + { + --i; + m->createForConfiguration (configuration, i); + + if (mListener) + mListener->materialCreated (m, configuration, i); + } + + m->createForConfiguration (configuration, lodIndex); + if (mListener) + mListener->materialCreated (m, configuration, lodIndex); + } + return m; + } + + MaterialInstance* Factory::createMaterialInstance (const std::string& name, const std::string& parentInstance) + { + if (parentInstance != "" && mMaterials.find(parentInstance) == mMaterials.end()) + throw std::runtime_error ("trying to clone material that does not exist"); + + MaterialInstance newInstance(name, this); + + if (!mShadersEnabled) + newInstance.setShadersEnabled(false); + + if (parentInstance != "") + newInstance.setParent (&mMaterials.find(parentInstance)->second); + + newInstance.create(mPlatform); + + mMaterials.insert (std::make_pair(name, newInstance)); + + return &mMaterials.find(name)->second; + } + + void Factory::destroyMaterialInstance (const std::string& name) + { + if (mMaterials.find(name) != mMaterials.end()) + mMaterials.erase(name); + } + + void Factory::setShadersEnabled (bool enabled) + { + mShadersEnabled = enabled; + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.setShadersEnabled(enabled); + } + } + + void Factory::setGlobalSetting (const std::string& name, const std::string& value) + { + bool changed = true; + if (mGlobalSettings.hasProperty(name)) + changed = (retrieveValue(mGlobalSettings.getProperty(name), NULL).get() != value); + + mGlobalSettings.setProperty (name, makeProperty(new StringValue(value))); + + if (changed) + { + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.destroyAll(); + } + } + } + + void Factory::setSharedParameter (const std::string& name, PropertyValuePtr value) + { + mPlatform->setSharedParameter(name, value); + } + + ShaderSet* Factory::getShaderSet (const std::string& name) + { + return &mShaderSets.find(name)->second; + } + + Platform* Factory::getPlatform () + { + return mPlatform; + } + + Language Factory::getCurrentLanguage () + { + return mCurrentLanguage; + } + + void Factory::setCurrentLanguage (Language lang) + { + bool changed = (mCurrentLanguage != lang); + mCurrentLanguage = lang; + + if (changed) + { + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.destroyAll(); + } + } + } + + MaterialInstance* Factory::getMaterialInstance (const std::string& name) + { + return findInstance(name); + } + + void Factory::setTextureAlias (const std::string& alias, const std::string& realName) + { + mTextureAliases[alias] = realName; + + // update the already existing texture units + for (std::map::iterator it = mTextureAliasInstances.begin(); it != mTextureAliasInstances.end(); ++it) + { + if (it->second == alias) + { + it->first->setTextureName(realName); + } + } + } + + std::string Factory::retrieveTextureAlias (const std::string& name) + { + if (mTextureAliases.find(name) != mTextureAliases.end()) + return mTextureAliases[name]; + else + return ""; + } + + PropertySetGet* Factory::getConfiguration (const std::string& name) + { + return &mConfigurations[name]; + } + + void Factory::registerConfiguration (const std::string& name, PropertySetGet configuration) + { + mConfigurations[name] = configuration; + mConfigurations[name].setParent (&mGlobalSettings); + } + + void Factory::registerLodConfiguration (int index, PropertySetGet configuration) + { + mLodConfigurations[index] = configuration; + } + + void Factory::setMaterialListener (MaterialListener* listener) + { + mListener = listener; + } + + void Factory::addTextureAliasInstance (const std::string& name, TextureUnitState* t) + { + mTextureAliasInstances[t] = name; + } + + void Factory::removeTextureAliasInstances (TextureUnitState* t) + { + mTextureAliasInstances.erase(t); + } + + void Factory::setActiveConfiguration (const std::string& configuration) + { + if (configuration == "Default") + mCurrentConfiguration = 0; + else + { + assert (mConfigurations.find(configuration) != mConfigurations.end()); + mCurrentConfiguration = &mConfigurations[configuration]; + } + } + + void Factory::setActiveLodLevel (int level) + { + if (level == 0) + mCurrentLodConfiguration = 0; + else + { + assert (mLodConfigurations.find(level) != mLodConfigurations.end()); + mCurrentLodConfiguration = &mLodConfigurations[level]; + } + } + + void Factory::setShaderDebugOutputEnabled (bool enabled) + { + mShaderDebugOutputEnabled = enabled; + } + + PropertySetGet* Factory::getCurrentGlobalSettings() + { + PropertySetGet* p = &mGlobalSettings; + + // current global settings are affected by active configuration & active lod configuration + + if (mCurrentConfiguration) + { + p = mCurrentConfiguration; + } + + if (mCurrentLodConfiguration) + { + mCurrentLodConfiguration->setParent(p); + p = mCurrentLodConfiguration; + } + + return p; + } + + void Factory::saveMaterials (const std::string& filename) + { + std::ofstream file; + file.open (filename.c_str ()); + + for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it) + { + it->second.save(file); + } + + file.close(); + } + + void Factory::_ensureMaterial(const std::string& name, const std::string& configuration) + { + MaterialInstance* m = searchInstance (name); + assert(m); + m->createForConfiguration (configuration, 0); + } +} diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp new file mode 100644 index 000000000..799dd71eb --- /dev/null +++ b/extern/shiny/Main/Factory.hpp @@ -0,0 +1,207 @@ +#ifndef SH_FACTORY_H +#define SH_FACTORY_H + +#include +#include + +#include "MaterialInstance.hpp" +#include "ShaderSet.hpp" +#include "Language.hpp" + +namespace sh +{ + class Platform; + + typedef std::map MaterialMap; + typedef std::map ShaderSetMap; + typedef std::map ConfigurationMap; + typedef std::map LodConfigurationMap; + typedef std::map LastModifiedMap; + + typedef std::map TextureAliasMap; + + /** + * @brief + * Allows you to be notified when a certain material was just created. Useful for changing material properties that you can't + * do in a .mat script (for example a series of animated textures) \n + * When receiving the event, you can get the platform material by calling m->getMaterial() + * and casting that to the platform specific material (e.g. for Ogre, sh::OgreMaterial) + */ + class MaterialListener + { + public: + virtual void materialCreated (MaterialInstance* m, const std::string& configuration, unsigned short lodIndex) = 0; + }; + + /** + * @brief + * The main interface class + */ + class Factory + { + public: + Factory(Platform* platform); + ///< @note Ownership of \a platform is transferred to this class, so you don't have to delete it. + + ~Factory(); + + /** + * Create a MaterialInstance, optionally copying all properties from \a parentInstance + * @param name name of the new instance + * @param name of the parent (optional) + * @return newly created instance + */ + MaterialInstance* createMaterialInstance (const std::string& name, const std::string& parentInstance = ""); + + /// @note It is safe to call this if the instance does not exist + void destroyMaterialInstance (const std::string& name); + + /// Use this to enable or disable shaders on-the-fly + void setShadersEnabled (bool enabled); + + /// write generated shaders to current directory, useful for debugging + void setShaderDebugOutputEnabled (bool enabled); + + /// Use this to manage user settings. \n + /// Global settings can be retrieved in shaders through a macro. \n + /// When a global setting is changed, the shaders that depend on them are recompiled automatically. + void setGlobalSetting (const std::string& name, const std::string& value); + + /// Adjusts the given shared parameter. \n + /// Internally, this will change all uniform parameters of this name marked with the macro \@shSharedParameter \n + /// @param name of the shared parameter + /// @param value of the parameter, use sh::makeProperty to construct this value + void setSharedParameter (const std::string& name, PropertyValuePtr value); + + Language getCurrentLanguage (); + + /// Switch between different shader languages (cg, glsl, hlsl) + void setCurrentLanguage (Language lang); + + /// Get a MaterialInstance by name + MaterialInstance* getMaterialInstance (const std::string& name); + + /// Register a configuration, which can then be used by switching the active material scheme + void registerConfiguration (const std::string& name, PropertySetGet configuration); + + /// Register a lod configuration, which can then be used by setting up lod distance values for the material \n + /// 0 refers to highest lod, so use 1 or higher as index parameter + void registerLodConfiguration (int index, PropertySetGet configuration); + + /// Set an alias name for a texture, the real name can then be retrieved with the "texture_alias" + /// property in a texture unit - this is useful if you don't know the name of your texture beforehand. \n + /// Example: \n + /// - In the material definition: texture_alias ReflectionMap \n + /// - At runtime: factory->setTextureAlias("ReflectionMap", "rtt_654654"); \n + /// You can call factory->setTextureAlias as many times as you want, and if the material was already created, its texture will be updated! + void setTextureAlias (const std::string& alias, const std::string& realName); + + /// Retrieve the real texture name for a texture alias (the real name is set by the user) + std::string retrieveTextureAlias (const std::string& name); + + /// Attach a listener for material created events + void setMaterialListener (MaterialListener* listener); + + /// Call this after you have set up basic stuff, like the shader language. + void loadAllFiles (); + + /// Controls writing of generated shader source code to the cache folder, so that the + /// (rather expensive) preprocessing step can be skipped on the next run. See Factory::setReadSourceCache \n + /// \note The default is off (no cache writing) + void setWriteSourceCache(bool write) { mWriteSourceCache = write; } + + /// Controls reading of generated shader sources from the cache folder + /// \note The default is off (no cache reading) + /// \note Even if microcode caching is enabled, generating (or caching) the source is still required due to the macros. + void setReadSourceCache(bool read) { mReadSourceCache = read; } + + /// Controls writing the microcode of the generated shaders to the cache folder. Microcode is machine independent + /// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform. + /// \note The default is off (no cache writing) + void setWriteMicrocodeCache(bool write) { mWriteMicrocodeCache = write; } + + /// Controls reading of shader microcode from the cache folder. Microcode is machine independent + /// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform. + /// \note The default is off (no cache reading) + void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; } + + /// Saves all the materials that were initially loaded from the file with this name + void saveMaterials (const std::string& filename); + + static Factory& getInstance(); + ///< Return instance of this class. + + static Factory* getInstancePtr(); + + /// Make sure a material technique is loaded.\n + /// You will probably never have to use this. + void _ensureMaterial(const std::string& name, const std::string& configuration); + + private: + + MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex); + ShaderSet* getShaderSet (const std::string& name); + PropertySetGet* getConfiguration (const std::string& name); + Platform* getPlatform (); + + PropertySetGet* getCurrentGlobalSettings(); + + void addTextureAliasInstance (const std::string& name, TextureUnitState* t); + void removeTextureAliasInstances (TextureUnitState* t); + + std::string getCacheFolder () { return mPlatform->getCacheFolder (); } + bool getReadSourceCache() { return mReadSourceCache; } + bool getWriteSourceCache() { return mReadSourceCache; } + public: + bool getWriteMicrocodeCache() { return mWriteMicrocodeCache; } // Fixme + + private: + void setActiveConfiguration (const std::string& configuration); + void setActiveLodLevel (int level); + + bool getShaderDebugOutputEnabled() { return mShaderDebugOutputEnabled; } + + std::map mTextureAliasInstances; + + friend class Platform; + friend class MaterialInstance; + friend class ShaderInstance; + friend class ShaderSet; + friend class TextureUnitState; + + private: + static Factory* sThis; + + bool mShadersEnabled; + bool mShaderDebugOutputEnabled; + + bool mReadMicrocodeCache; + bool mWriteMicrocodeCache; + bool mReadSourceCache; + bool mWriteSourceCache; + + MaterialMap mMaterials; + ShaderSetMap mShaderSets; + ConfigurationMap mConfigurations; + LodConfigurationMap mLodConfigurations; + LastModifiedMap mShadersLastModified; + + PropertySetGet mGlobalSettings; + + PropertySetGet* mCurrentConfiguration; + PropertySetGet* mCurrentLodConfiguration; + + TextureAliasMap mTextureAliases; + + Language mCurrentLanguage; + + MaterialListener* mListener; + + Platform* mPlatform; + + MaterialInstance* findInstance (const std::string& name); + MaterialInstance* searchInstance (const std::string& name); + }; +} + +#endif diff --git a/extern/shiny/Main/Language.hpp b/extern/shiny/Main/Language.hpp new file mode 100644 index 000000000..20bf8ed61 --- /dev/null +++ b/extern/shiny/Main/Language.hpp @@ -0,0 +1,16 @@ +#ifndef SH_LANGUAGE_H +#define SH_LANGUAGE_H + +namespace sh +{ + enum Language + { + Language_CG, + Language_HLSL, + Language_GLSL, + Language_Count, + Language_None + }; +} + +#endif diff --git a/extern/shiny/Main/MaterialInstance.cpp b/extern/shiny/Main/MaterialInstance.cpp new file mode 100644 index 000000000..0f8bcdda7 --- /dev/null +++ b/extern/shiny/Main/MaterialInstance.cpp @@ -0,0 +1,220 @@ +#include "MaterialInstance.hpp" + +#include + +#include "Factory.hpp" +#include "ShaderSet.hpp" + +namespace sh +{ + MaterialInstance::MaterialInstance (const std::string& name, Factory* f) + : mName(name) + , mShadersEnabled(true) + , mFactory(f) + , mListener(NULL) + { + } + + MaterialInstance::~MaterialInstance () + { + } + + void MaterialInstance::setParentInstance (const std::string& name) + { + mParentInstance = name; + } + + std::string MaterialInstance::getParentInstance () + { + return mParentInstance; + } + + void MaterialInstance::create (Platform* platform) + { + mMaterial = platform->createMaterial(mName); + + if (hasProperty ("shadow_caster_material")) + mMaterial->setShadowCasterMaterial (retrieveValue(getProperty("shadow_caster_material"), NULL).get()); + + if (hasProperty ("lod_values")) + mMaterial->setLodLevels (retrieveValue(getProperty("lod_values"), NULL).get()); + } + + void MaterialInstance::destroyAll () + { + if (hasProperty("create_configuration")) + return; + mMaterial->removeAll(); + mTexUnits.clear(); + } + + void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value) + { + PropertySetGet::setProperty (name, value); + destroyAll(); // trigger updates + } + + void MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex) + { + bool res = mMaterial->createConfiguration(configuration, lodIndex); + if (!res) + return; // listener was false positive + + if (mListener) + mListener->requestedConfiguration (this, configuration); + + mFactory->setActiveConfiguration (configuration); + mFactory->setActiveLodLevel (lodIndex); + + bool allowFixedFunction = true; + if (!mShadersEnabled && hasProperty("allow_fixed_function")) + { + allowFixedFunction = retrieveValue(getProperty("allow_fixed_function"), NULL).get(); + } + + bool useShaders = mShadersEnabled || !allowFixedFunction; + + // get passes of the top-most parent + PassVector passes = getPasses(); + if (passes.size() == 0) + throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); + + for (PassVector::iterator it = passes.begin(); it != passes.end(); ++it) + { + boost::shared_ptr pass = mMaterial->createPass (configuration, lodIndex); + it->copyAll (pass.get(), this); + + // texture samplers used in the shaders + std::vector usedTextureSamplersVertex; + std::vector usedTextureSamplersFragment; + + PropertySetGet* context = this; + + // create or retrieve shaders + bool hasVertex = it->hasProperty("vertex_program"); + bool hasFragment = it->hasProperty("fragment_program"); + if (useShaders) + { + it->setContext(context); + it->mShaderProperties.setContext(context); + if (hasVertex) + { + ShaderSet* vertex = mFactory->getShaderSet(retrieveValue(it->getProperty("vertex_program"), context).get()); + ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); + if (v) + { + pass->assignProgram (GPT_Vertex, v->getName()); + v->setUniformParameters (pass, &it->mShaderProperties); + + std::vector sharedParams = v->getSharedParameters (); + for (std::vector::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it) + { + pass->addSharedParameter (GPT_Vertex, *it); + } + + std::vector vector = v->getUsedSamplers (); + usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); + } + } + if (hasFragment) + { + ShaderSet* fragment = mFactory->getShaderSet(retrieveValue(it->getProperty("fragment_program"), context).get()); + ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); + if (f) + { + pass->assignProgram (GPT_Fragment, f->getName()); + f->setUniformParameters (pass, &it->mShaderProperties); + + std::vector sharedParams = f->getSharedParameters (); + for (std::vector::iterator it = sharedParams.begin(); it != sharedParams.end(); ++it) + { + pass->addSharedParameter (GPT_Fragment, *it); + } + + std::vector vector = f->getUsedSamplers (); + usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); + } + } + } + + // create texture units + std::vector texUnits = it->getTexUnits(); + int i=0; + for (std::vector::iterator texIt = texUnits.begin(); texIt != texUnits.end(); ++texIt ) + { + // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled + bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); + bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); + if ( (foundVertex || foundFragment) + || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue(texIt->getProperty("create_in_ffp"), this).get())) + { + boost::shared_ptr texUnit = pass->createTextureUnitState (); + texIt->copyAll (texUnit.get(), context); + + mTexUnits.push_back(texUnit); + + // set texture unit indices (required by GLSL) + if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && mFactory->getCurrentLanguage () == Language_GLSL) + { + pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); + + ++i; + } + } + } + } + + if (mListener) + mListener->createdConfiguration (this, configuration); + } + + Material* MaterialInstance::getMaterial () + { + return mMaterial.get(); + } + + MaterialInstancePass* MaterialInstance::createPass () + { + mPasses.push_back (MaterialInstancePass()); + mPasses.back().setContext(this); + return &mPasses.back(); + } + + PassVector MaterialInstance::getPasses() + { + if (mParent) + return static_cast(mParent)->getPasses(); + else + return mPasses; + } + + void MaterialInstance::setShadersEnabled (bool enabled) + { + if (enabled == mShadersEnabled) + return; + mShadersEnabled = enabled; + + // trigger updates + if (mMaterial.get()) + destroyAll(); + } + + void MaterialInstance::save (std::ofstream& stream) + { + stream << "material " << mName << "\n" + << "{\n"; + + if (mParent) + { + stream << "\t" << static_cast(mParent)->getName() << "\n"; + } + + const PropertyMap& properties = listProperties (); + for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) + { + stream << "\t" << it->first << " " << retrieveValue(getProperty(it->first), NULL).get() << "\n"; + } + + stream << "}\n"; + } +} diff --git a/extern/shiny/Main/MaterialInstance.hpp b/extern/shiny/Main/MaterialInstance.hpp new file mode 100644 index 000000000..000f9d60c --- /dev/null +++ b/extern/shiny/Main/MaterialInstance.hpp @@ -0,0 +1,104 @@ +#ifndef SH_MATERIALINSTANCE_H +#define SH_MATERIALINSTANCE_H + +#include +#include + +#include "PropertyBase.hpp" +#include "Platform.hpp" +#include "MaterialInstancePass.hpp" + +namespace sh +{ + class Factory; + + typedef std::vector PassVector; + + /** + * @brief + * Allows you to be notified when a certain configuration for a material was just about to be created. \n + * Useful for adjusting some properties prior to the material being created (Or you could also re-create + * the whole material from scratch, i.e. use this as a method to create this material entirely in code) + */ + class MaterialInstanceListener + { + public: + virtual void requestedConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called before creating + virtual void createdConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called after creating + }; + + /** + * @brief + * A specific material instance, which has all required properties set + * (for example the diffuse & normal map, ambient/diffuse/specular values). \n + * Depending on these properties, the system will automatically select a shader permutation + * that suits these and create the backend materials / passes (provided by the \a Platform class). + */ + class MaterialInstance : public PropertySetGet + { + public: + MaterialInstance (const std::string& name, Factory* f); + virtual ~MaterialInstance (); + + MaterialInstancePass* createPass (); + PassVector getPasses(); ///< gets the passes of the top-most parent + + /// @attention Because the backend material passes are created on demand, the returned material here might not contain anything yet! + /// The only place where you should use this method, is for the MaterialInstance given by the MaterialListener::materialCreated event! + Material* getMaterial(); + + /// attach a \a MaterialInstanceListener to this specific material (as opposed to \a MaterialListener, which listens to all materials) + void setListener (MaterialInstanceListener* l) { mListener = l; } + + std::string getName() { return mName; } + + virtual void setProperty (const std::string& name, PropertyValuePtr value); + + private: + void setParentInstance (const std::string& name); + std::string getParentInstance (); + + void create (Platform* platform); + void createForConfiguration (const std::string& configuration, unsigned short lodIndex); + + void destroyAll (); + + void setShadersEnabled (bool enabled); + + void setSourceFile(const std::string& sourceFile) { mSourceFile = sourceFile; } + + std::string getSourceFile() { return mSourceFile; } + ///< get the name of the file this material was read from, or empty if it was created dynamically by code + + void save (std::ofstream& stream); + ///< this will only save the properties, not the passes and texture units, and as such + /// is only intended to be used for derived materials + + friend class Factory; + + + private: + std::string mParentInstance; + ///< this is only used during the file-loading phase. an instance could be loaded before its parent is loaded, + /// so initially only the parent's name is written to this member. + /// once all instances are loaded, the actual mParent pointer (from PropertySetGet class) can be set + + std::vector< boost::shared_ptr > mTexUnits; + + MaterialInstanceListener* mListener; + + PassVector mPasses; + + std::string mName; + + std::string mSourceFile; + + boost::shared_ptr mMaterial; + + bool mShadersEnabled; + + Factory* mFactory; + }; +} + +#endif diff --git a/extern/shiny/Main/MaterialInstancePass.cpp b/extern/shiny/Main/MaterialInstancePass.cpp new file mode 100644 index 000000000..b14476f4e --- /dev/null +++ b/extern/shiny/Main/MaterialInstancePass.cpp @@ -0,0 +1,16 @@ +#include "MaterialInstancePass.hpp" + +namespace sh +{ + + MaterialInstanceTextureUnit* MaterialInstancePass::createTextureUnit (const std::string& name) + { + mTexUnits.push_back(MaterialInstanceTextureUnit(name)); + return &mTexUnits.back(); + } + + std::vector MaterialInstancePass::getTexUnits () + { + return mTexUnits; + } +} diff --git a/extern/shiny/Main/MaterialInstancePass.hpp b/extern/shiny/Main/MaterialInstancePass.hpp new file mode 100644 index 000000000..7d7330f70 --- /dev/null +++ b/extern/shiny/Main/MaterialInstancePass.hpp @@ -0,0 +1,29 @@ +#ifndef SH_MATERIALINSTANCEPASS_H +#define SH_MATERIALINSTANCEPASS_H + +#include + +#include "PropertyBase.hpp" +#include "MaterialInstanceTextureUnit.hpp" + +namespace sh +{ + /** + * @brief + * Holds properties of a single texture unit in a \a MaterialInstancePass. \n + * No inheritance here for now. + */ + class MaterialInstancePass : public PropertySetGet + { + public: + MaterialInstanceTextureUnit* createTextureUnit (const std::string& name); + + PropertySetGet mShaderProperties; + + std::vector getTexUnits (); + private: + std::vector mTexUnits; + }; +} + +#endif diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.cpp b/extern/shiny/Main/MaterialInstanceTextureUnit.cpp new file mode 100644 index 000000000..0e3078af3 --- /dev/null +++ b/extern/shiny/Main/MaterialInstanceTextureUnit.cpp @@ -0,0 +1,14 @@ +#include "MaterialInstanceTextureUnit.hpp" + +namespace sh +{ + MaterialInstanceTextureUnit::MaterialInstanceTextureUnit (const std::string& name) + : mName(name) + { + } + + std::string MaterialInstanceTextureUnit::getName() const + { + return mName; + } +} diff --git a/extern/shiny/Main/MaterialInstanceTextureUnit.hpp b/extern/shiny/Main/MaterialInstanceTextureUnit.hpp new file mode 100644 index 000000000..ae9f54fd2 --- /dev/null +++ b/extern/shiny/Main/MaterialInstanceTextureUnit.hpp @@ -0,0 +1,26 @@ +#ifndef SH_MATERIALINSTANCETEXTUREUNIT_H +#define SH_MATERIALINSTANCETEXTUREUNIT_H + +#include "PropertyBase.hpp" + +namespace sh +{ + /** + * @brief + * A single texture unit state that belongs to a \a MaterialInstancePass \n + * this is not the real "backend" \a TextureUnitState (provided by \a Platform), + * it is merely a placeholder for properties. \n + * @note The backend \a TextureUnitState will only be created if this texture unit is + * actually used (i.e. referenced in the shader, or marked with property create_in_ffp = true). + */ + class MaterialInstanceTextureUnit : public PropertySetGet + { + public: + MaterialInstanceTextureUnit (const std::string& name); + std::string getName() const; + private: + std::string mName; + }; +} + +#endif diff --git a/extern/shiny/Main/Platform.cpp b/extern/shiny/Main/Platform.cpp new file mode 100644 index 000000000..94b4f872a --- /dev/null +++ b/extern/shiny/Main/Platform.cpp @@ -0,0 +1,94 @@ +#include "Platform.hpp" + +#include + +#include "Factory.hpp" + +namespace sh +{ + Platform::Platform (const std::string& basePath) + : mBasePath(basePath) + , mCacheFolder("./") + , mShaderCachingEnabled(false) + { + } + + Platform::~Platform () + { + } + + void Platform::setFactory (Factory* factory) + { + mFactory = factory; + } + + std::string Platform::getBasePath () + { + return mBasePath; + } + + bool Platform::supportsMaterialQueuedListener () + { + return false; + } + + bool Platform::supportsShaderSerialization () + { + return false; + } + + MaterialInstance* Platform::fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex) + { + return mFactory->requestMaterial (name, configuration, lodIndex); + } + + void Platform::serializeShaders (const std::string& file) + { + throw std::runtime_error ("Shader serialization not supported by this platform"); + } + + void Platform::deserializeShaders (const std::string& file) + { + throw std::runtime_error ("Shader serialization not supported by this platform"); + } + + void Platform::setCacheFolder (const std::string& folder) + { + mCacheFolder = folder; + } + + void Platform::setShaderCachingEnabled (bool enabled) + { + mShaderCachingEnabled = enabled; + } + + std::string Platform::getCacheFolder() const + { + return mCacheFolder; + } + + // ------------------------------------------------------------------------------ + + bool TextureUnitState::setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context) + { + if (name == "texture_alias") + { + std::string aliasName = retrieveValue(value, context).get(); + + Factory::getInstance().addTextureAliasInstance (aliasName, this); + + setTextureName (Factory::getInstance().retrieveTextureAlias (aliasName)); + + return true; + } + else + return false; + } + + TextureUnitState::~TextureUnitState() + { + Factory* f = Factory::getInstancePtr (); + if (f) + f->removeTextureAliasInstances (this); + } +} diff --git a/extern/shiny/Main/Platform.hpp b/extern/shiny/Main/Platform.hpp new file mode 100644 index 000000000..1b095e957 --- /dev/null +++ b/extern/shiny/Main/Platform.hpp @@ -0,0 +1,145 @@ +#ifndef SH_PLATFORM_H +#define SH_PLATFORM_H + +#include + +#include + +#include "Language.hpp" +#include "PropertyBase.hpp" + +namespace sh +{ + class Factory; + class MaterialInstance; + + enum GpuProgramType + { + GPT_Vertex, + GPT_Fragment + // GPT_Geometry + }; + + // These classes are supposed to be filled by the platform implementation + class GpuProgram + { + public: + virtual bool getSupported () = 0; ///< @return true if the compilation was successful + + /// @param name name of the uniform in the shader + /// @param autoConstantName name of the auto constant (for example world_viewproj_matrix) + /// @param extraInfo if any extra info is needed (e.g. light index), put it here + virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = "") = 0; + }; + + class TextureUnitState : public PropertySet + { + public: + virtual ~TextureUnitState(); + + virtual void setTextureName (const std::string& textureName) = 0; + + protected: + virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet *context); + }; + + class Pass : public PropertySet + { + public: + virtual boost::shared_ptr createTextureUnitState () = 0; + virtual void assignProgram (GpuProgramType type, const std::string& name) = 0; + + /// @param type gpu program type + /// @param name name of the uniform in the shader + /// @param vt type of value, e.g. vector4 + /// @param value value to set + /// @param context used for retrieving linked values + virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) = 0; + + virtual void setTextureUnitIndex (int programType, const std::string& name, int index) = 0; + + virtual void addSharedParameter (int type, const std::string& name) = 0; + }; + + class Material : public PropertySet + { + public: + virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex) = 0; + virtual bool createConfiguration (const std::string& name, unsigned short lodIndex) = 0; ///< @return false if already exists + virtual void removeAll () = 0; ///< remove all configurations + + virtual void setLodLevels (const std::string& lodLevels) = 0; + + virtual void setShadowCasterMaterial (const std::string& name) = 0; + }; + + class Platform + { + public: + Platform (const std::string& basePath); + virtual ~Platform (); + + void setShaderCachingEnabled (bool enabled); + + /// set the folder to use for shader caching + void setCacheFolder (const std::string& folder); + + private: + virtual boost::shared_ptr createMaterial (const std::string& name) = 0; + + virtual boost::shared_ptr createGpuProgram ( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, Language lang) = 0; + + virtual void setSharedParameter (const std::string& name, PropertyValuePtr value) = 0; + + virtual bool isProfileSupported (const std::string& profile) = 0; + + virtual void serializeShaders (const std::string& file); + virtual void deserializeShaders (const std::string& file); + + std::string getCacheFolder () const; + + friend class Factory; + friend class MaterialInstance; + friend class ShaderInstance; + + protected: + /** + * this will be \a true if the platform supports serialization (writing shader microcode + * to disk) and deserialization (create gpu program from saved microcode) + */ + virtual bool supportsShaderSerialization (); + + /** + * this will be \a true if the platform supports a listener that notifies the system + * whenever a material is requested for rendering. if this is supported, shaders can be + * compiled on-demand when needed (and not earlier) + * @todo the Factory is not designed yet to handle the case where this method returns false + */ + virtual bool supportsMaterialQueuedListener (); + + /** + * fire event: material requested for rendering + * @param name material name + * @param configuration requested configuration + */ + MaterialInstance* fireMaterialRequested (const std::string& name, const std::string& configuration, unsigned short lodIndex); + + std::string mCacheFolder; + Factory* mFactory; + + protected: + bool mShaderCachingEnabled; + + private: + void setFactory (Factory* factory); + + std::string mBasePath; + std::string getBasePath(); + }; +} + +#endif diff --git a/extern/shiny/Main/Preprocessor.cpp b/extern/shiny/Main/Preprocessor.cpp new file mode 100644 index 000000000..1a97668bc --- /dev/null +++ b/extern/shiny/Main/Preprocessor.cpp @@ -0,0 +1,99 @@ +#include "Preprocessor.hpp" + +#include +#include +#include + +namespace sh +{ + std::string Preprocessor::preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name) + { + std::stringstream returnString; + + // current file position is saved for exception handling + boost::wave::util::file_position_type current_position; + + try + { + // This token type is one of the central types used throughout the library. + // It is a template parameter to some of the public classes and instances + // of this type are returned from the iterators. + typedef boost::wave::cpplexer::lex_token<> token_type; + + // The template boost::wave::cpplexer::lex_iterator<> is the lexer type to + // to use as the token source for the preprocessing engine. It is + // parametrized with the token type. + typedef boost::wave::cpplexer::lex_iterator lex_iterator_type; + + // This is the resulting context type. The first template parameter should + // match the iterator type used during construction of the context + // instance (see below). It is the type of the underlying input stream. + typedef boost::wave::context + context_type; + + // The preprocessor iterator shouldn't be constructed directly. It is + // generated through a wave::context<> object. This wave:context<> object + // is additionally used to initialize and define different parameters of + // the actual preprocessing. + // + // The preprocessing of the input stream is done on the fly behind the + // scenes during iteration over the range of context_type::iterator_type + // instances. + context_type ctx (source.begin(), source.end(), name.c_str()); + ctx.add_include_path(includePath.c_str()); + for (std::vector::iterator it = definitions.begin(); it != definitions.end(); ++it) + { + ctx.add_macro_definition(*it); + } + + // Get the preprocessor iterators and use them to generate the token + // sequence. + context_type::iterator_type first = ctx.begin(); + context_type::iterator_type last = ctx.end(); + + // The input stream is preprocessed for you while iterating over the range + // [first, last). The dereferenced iterator returns tokens holding + // information about the preprocessed input stream, such as token type, + // token value, and position. + while (first != last) + { + current_position = (*first).get_position(); + returnString << (*first).get_value(); + ++first; + } + } + catch (boost::wave::cpp_exception const& e) + { + // some preprocessing error + std::stringstream error; + error + << e.file_name() << "(" << e.line_no() << "): " + << e.description(); + throw std::runtime_error(error.str()); + } + catch (std::exception const& e) + { + // use last recognized token to retrieve the error position + std::stringstream error; + error + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "exception caught: " << e.what(); + throw std::runtime_error(error.str()); + } + catch (...) + { + // use last recognized token to retrieve the error position + std::stringstream error; + error + << current_position.get_file() + << "(" << current_position.get_line() << "): " + << "unexpected exception caught."; + throw std::runtime_error(error.str()); + } + + return returnString.str(); + } +} diff --git a/extern/shiny/Main/Preprocessor.hpp b/extern/shiny/Main/Preprocessor.hpp new file mode 100644 index 000000000..7ee30ae7f --- /dev/null +++ b/extern/shiny/Main/Preprocessor.hpp @@ -0,0 +1,69 @@ +#ifndef SH_PREPROCESSOR_H +#define SH_PREPROCESSOR_H + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace sh +{ + /** + * @brief A simple interface for the boost::wave preprocessor + */ + class Preprocessor + { + public: + /** + * @brief Run a shader source string through the preprocessor + * @param source source string + * @param includePath path to search for includes (that are included with #include) + * @param definitions macros to predefine (vector of strings of the format MACRO=value, or just MACRO to define it as 1) + * @param name name to use for error messages + * @return processed string + */ + static std::string preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name); + }; + + + + class emit_custom_line_directives_hooks + : public boost::wave::context_policies::default_preprocessing_hooks + { + public: + + template + bool + emit_line_directive(ContextT const& ctx, ContainerT &pending, + typename ContextT::token_type const& act_token) + { + // emit a #line directive showing the relative filename instead + typename ContextT::position_type pos = act_token.get_position(); + unsigned int column = 1; + + typedef typename ContextT::token_type result_type; + + // no line directives for now + pos.set_column(column); + pending.push_back(result_type(boost::wave::T_GENERATEDNEWLINE, "\n", pos)); + + return true; + } + }; + + +} + +#endif diff --git a/extern/shiny/Main/PropertyBase.cpp b/extern/shiny/Main/PropertyBase.cpp new file mode 100644 index 000000000..0c39e5c1e --- /dev/null +++ b/extern/shiny/Main/PropertyBase.cpp @@ -0,0 +1,268 @@ +#include "PropertyBase.hpp" + +#include +#include + +#include +#include + +namespace sh +{ + + IntValue::IntValue(int in) + : mValue(in) + { + } + + IntValue::IntValue(const std::string& in) + { + mValue = boost::lexical_cast(in); + } + + std::string IntValue::serialize() + { + return boost::lexical_cast(mValue); + } + + // ------------------------------------------------------------------------------ + + BooleanValue::BooleanValue (bool in) + : mValue(in) + { + } + + BooleanValue::BooleanValue (const std::string& in) + { + if (in == "true") + mValue = true; + else if (in == "false") + mValue = false; + else + { + std::cerr << "sh::BooleanValue: Warning: Unrecognized value \"" << in << "\" for property value of type BooleanValue" << std::endl; + mValue = false; + } + } + + std::string BooleanValue::serialize () + { + if (mValue) + return "true"; + else + return "false"; + } + + // ------------------------------------------------------------------------------ + + StringValue::StringValue (const std::string& in) + { + mStringValue = in; + } + + std::string StringValue::serialize() + { + return mStringValue; + } + + // ------------------------------------------------------------------------------ + + LinkedValue::LinkedValue (const std::string& in) + { + mStringValue = in; + mStringValue.erase(0, 1); + } + + std::string LinkedValue::serialize() + { + throw std::runtime_error ("can't directly get a linked value"); + } + + std::string LinkedValue::get(PropertySetGet* context) const + { + PropertyValuePtr p = context->getProperty(mStringValue); + return retrieveValue(p, NULL).get(); + } + + // ------------------------------------------------------------------------------ + + FloatValue::FloatValue (float in) + { + mValue = in; + } + + FloatValue::FloatValue (const std::string& in) + { + mValue = boost::lexical_cast(in); + } + + std::string FloatValue::serialize () + { + return boost::lexical_cast(mValue); + } + + // ------------------------------------------------------------------------------ + + Vector2::Vector2 (float x, float y) + : mX(x) + , mY(y) + { + } + + Vector2::Vector2 (const std::string& in) + { + std::vector tokens; + boost::split(tokens, in, boost::is_any_of(" ")); + assert ((tokens.size() == 2) && "Invalid Vector2 conversion"); + mX = boost::lexical_cast (tokens[0]); + mY = boost::lexical_cast (tokens[1]); + } + + std::string Vector2::serialize () + { + return boost::lexical_cast(mX) + " " + + boost::lexical_cast(mY); + } + + // ------------------------------------------------------------------------------ + + Vector3::Vector3 (float x, float y, float z) + : mX(x) + , mY(y) + , mZ(z) + { + } + + Vector3::Vector3 (const std::string& in) + { + std::vector tokens; + boost::split(tokens, in, boost::is_any_of(" ")); + assert ((tokens.size() == 3) && "Invalid Vector3 conversion"); + mX = boost::lexical_cast (tokens[0]); + mY = boost::lexical_cast (tokens[1]); + mZ = boost::lexical_cast (tokens[2]); + } + + std::string Vector3::serialize () + { + return boost::lexical_cast(mX) + " " + + boost::lexical_cast(mY) + " " + + boost::lexical_cast(mZ); + } + + // ------------------------------------------------------------------------------ + + Vector4::Vector4 (float x, float y, float z, float w) + : mX(x) + , mY(y) + , mZ(z) + , mW(w) + { + } + + Vector4::Vector4 (const std::string& in) + { + std::vector tokens; + boost::split(tokens, in, boost::is_any_of(" ")); + assert ((tokens.size() == 4) && "Invalid Vector4 conversion"); + mX = boost::lexical_cast (tokens[0]); + mY = boost::lexical_cast (tokens[1]); + mZ = boost::lexical_cast (tokens[2]); + mW = boost::lexical_cast (tokens[3]); + } + + std::string Vector4::serialize () + { + return boost::lexical_cast(mX) + " " + + boost::lexical_cast(mY) + " " + + boost::lexical_cast(mZ) + " " + + boost::lexical_cast(mW); + } + + // ------------------------------------------------------------------------------ + + void PropertySet::setProperty (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) + { + if (!setPropertyOverride (name, value, context)) + std::cerr << "sh::PropertySet: Warning: No match for property with name '" << name << "'" << std::endl; + } + + bool PropertySet::setPropertyOverride (const std::string& name, PropertyValuePtr &value, PropertySetGet* context) + { + // if we got here, none of the sub-classes was able to make use of the property + return false; + } + + // ------------------------------------------------------------------------------ + + PropertySetGet::PropertySetGet (PropertySetGet* parent) + : mParent(parent) + , mContext(NULL) + { + } + + PropertySetGet::PropertySetGet () + : mParent(NULL) + , mContext(NULL) + { + } + + void PropertySetGet::setParent (PropertySetGet* parent) + { + mParent = parent; + } + + void PropertySetGet::setContext (PropertySetGet* context) + { + mContext = context; + } + + PropertySetGet* PropertySetGet::getContext() + { + return mContext; + } + + void PropertySetGet::setProperty (const std::string& name, PropertyValuePtr value) + { + mProperties [name] = value; + } + + PropertyValuePtr& PropertySetGet::getProperty (const std::string& name) + { + bool found = (mProperties.find(name) != mProperties.end()); + + if (!found) + { + if (!mParent) + throw std::runtime_error ("Trying to retrieve property \"" + name + "\" that does not exist"); + else + return mParent->getProperty (name); + } + else + return mProperties[name]; + } + + bool PropertySetGet::hasProperty (const std::string& name) + { + bool found = (mProperties.find(name) != mProperties.end()); + + if (!found) + { + if (!mParent) + return false; + else + return mParent->hasProperty (name); + } + else + return true; + } + + void PropertySetGet::copyAll (PropertySet* target, PropertySetGet* context) + { + if (mParent) + mParent->copyAll (target, context); + for (PropertyMap::iterator it = mProperties.begin(); it != mProperties.end(); ++it) + { + target->setProperty(it->first, it->second, context); + } + } +} diff --git a/extern/shiny/Main/PropertyBase.hpp b/extern/shiny/Main/PropertyBase.hpp new file mode 100644 index 000000000..240acce81 --- /dev/null +++ b/extern/shiny/Main/PropertyBase.hpp @@ -0,0 +1,235 @@ +#ifndef SH_PROPERTYBASE_H +#define SH_PROPERTYBASE_H + +#include +#include + +#include + +namespace sh +{ + class StringValue; + class PropertySetGet; + class LinkedValue; + + enum ValueType + { + VT_String, + VT_Int, + VT_Float, + VT_Vector2, + VT_Vector3, + VT_Vector4 + }; + + class PropertyValue + { + public: + PropertyValue() {} + + virtual ~PropertyValue() {} + + std::string _getStringValue() { return mStringValue; } + + virtual std::string serialize() = 0; + + protected: + std::string mStringValue; ///< this will possibly not contain anything in the specialised classes + }; + typedef boost::shared_ptr PropertyValuePtr; + + class StringValue : public PropertyValue + { + public: + StringValue (const std::string& in); + std::string get() const { return mStringValue; } + + virtual std::string serialize(); + }; + + /** + * @brief Used for retrieving a named property from a context + */ + class LinkedValue : public PropertyValue + { + public: + LinkedValue (const std::string& in); + + std::string get(PropertySetGet* context) const; + + virtual std::string serialize(); + }; + + class FloatValue : public PropertyValue + { + public: + FloatValue (float in); + FloatValue (const std::string& in); + float get() const { return mValue; } + + virtual std::string serialize(); + private: + float mValue; + }; + + class IntValue : public PropertyValue + { + public: + IntValue (int in); + IntValue (const std::string& in); + int get() const { return mValue; } + + virtual std::string serialize(); + private: + int mValue; + }; + + class BooleanValue : public PropertyValue + { + public: + BooleanValue (bool in); + BooleanValue (const std::string& in); + bool get() const { return mValue; } + + virtual std::string serialize(); + private: + bool mValue; + }; + + class Vector2 : public PropertyValue + { + public: + Vector2 (float x, float y); + Vector2 (const std::string& in); + + float mX, mY; + + virtual std::string serialize(); + }; + + class Vector3 : public PropertyValue + { + public: + Vector3 (float x, float y, float z); + Vector3 (const std::string& in); + + float mX, mY, mZ; + + virtual std::string serialize(); + }; + + class Vector4 : public PropertyValue + { + public: + Vector4 (float x, float y, float z, float w); + Vector4 (const std::string& in); + + float mX, mY, mZ, mW; + + virtual std::string serialize(); + }; + + /// \brief base class that allows setting properties with any kind of value-type + class PropertySet + { + public: + void setProperty (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); + + protected: + virtual bool setPropertyOverride (const std::string& name, PropertyValuePtr& value, PropertySetGet* context); + ///< @return \a true if the specified property was found, or false otherwise + }; + + typedef std::map PropertyMap; + + /// \brief base class that allows setting properties with any kind of value-type and retrieving them + class PropertySetGet + { + public: + PropertySetGet (PropertySetGet* parent); + PropertySetGet (); + + virtual ~PropertySetGet() {} + + void copyAll (PropertySet* target, PropertySetGet* context); ///< call setProperty for each property/value pair stored in \a this + + void setParent (PropertySetGet* parent); + void setContext (PropertySetGet* context); + PropertySetGet* getContext(); + + virtual void setProperty (const std::string& name, PropertyValuePtr value); + PropertyValuePtr& getProperty (const std::string& name); + + const PropertyMap& listProperties() { return mProperties; } + + bool hasProperty (const std::string& name); + + private: + PropertyMap mProperties; + + protected: + PropertySetGet* mParent; + ///< the parent can provide properties as well (when they are retrieved via getProperty) \n + /// multiple levels of inheritance are also supported \n + /// children can override properties of their parents + + PropertySetGet* mContext; + ///< used to retrieve linked property values + }; + + template + static T retrieveValue (boost::shared_ptr& value, PropertySetGet* context) + { + if (typeid(*value).name() == typeid(LinkedValue).name()) + { + std::string v = static_cast(value.get())->get(context); + PropertyValuePtr newVal = PropertyValuePtr (new StringValue(v)); + return retrieveValue(newVal, NULL); + } + if (typeid(T).name() == typeid(*value).name()) + { + // requested type is the same as source type, only have to cast it + return *static_cast(value.get()); + } + + if ((typeid(T).name() == typeid(StringValue).name()) + && typeid(*value).name() != typeid(StringValue).name()) + { + // if string type is requested and value is not string, use serialize method to convert to string + T* ptr = new T (value->serialize()); // note that T is always StringValue here, but we can't use it here + value = boost::shared_ptr (static_cast(ptr)); + return *ptr; + } + + { + // remaining case: deserialization from string by passing the string to constructor of class T + T* ptr = new T(value->_getStringValue()); + PropertyValuePtr newVal (static_cast(ptr)); + value = newVal; + return *ptr; + } + } + ///< + /// @brief alternate version that supports linked values (use of $variables in parent material) + /// @note \a value is changed in-place to the converted object + /// @return converted object \n + + /// Create a property from a string + inline PropertyValuePtr makeProperty (const std::string& prop) + { + if (prop.size() > 1 && prop[0] == '$') + return PropertyValuePtr (static_cast(new LinkedValue(prop))); + else + return PropertyValuePtr (static_cast (new StringValue(prop))); + } + + template + /// Create a property of any type + /// Example: sh::makeProperty\ (new sh::Vector4(1, 1, 1, 1)) + inline PropertyValuePtr makeProperty (T* p) + { + return PropertyValuePtr ( static_cast(p) ); + } +} + +#endif diff --git a/extern/shiny/Main/ScriptLoader.cpp b/extern/shiny/Main/ScriptLoader.cpp new file mode 100644 index 000000000..a8971dc87 --- /dev/null +++ b/extern/shiny/Main/ScriptLoader.cpp @@ -0,0 +1,401 @@ +#include "ScriptLoader.hpp" + +#include +#include +#include +#include + +#include + +namespace sh +{ + void ScriptLoader::loadAllFiles(ScriptLoader* c, const std::string& path) + { + for ( boost::filesystem::recursive_directory_iterator end, dir(path); dir != end; ++dir ) + { + boost::filesystem::path p(*dir); + if(p.extension() == c->m_fileEnding) + { + c->m_currentFileName = (*dir).path().string(); + std::ifstream in((*dir).path().string().c_str(), std::ios::binary); + c->parseScript(in); + } + } + } + + ScriptLoader::ScriptLoader(const std::string& fileEnding) + { + m_fileEnding = fileEnding; + } + + ScriptLoader::~ScriptLoader() + { + clearScriptList(); + } + + void ScriptLoader::clearScriptList() + { + std::map ::iterator i; + for (i = m_scriptList.begin(); i != m_scriptList.end(); i++) + { + delete i->second; + } + m_scriptList.clear(); + } + + ScriptNode *ScriptLoader::getConfigScript(const std::string &name) + { + std::map ::iterator i; + + std::string key = name; + i = m_scriptList.find(key); + + //If found.. + if (i != m_scriptList.end()) + { + return i->second; + } + else + { + return NULL; + } + } + + std::map ScriptLoader::getAllConfigScripts () + { + return m_scriptList; + } + + void ScriptLoader::parseScript(std::ifstream &stream) + { + //Get first token + _nextToken(stream); + if (tok == TOKEN_EOF) + { + stream.close(); + return; + } + + //Parse the script + _parseNodes(stream, 0); + + stream.close(); + } + + void ScriptLoader::_nextToken(std::ifstream &stream) + { + //EOF token + if (!stream.good()) + { + tok = TOKEN_EOF; + return; + } + + //(Get next character) + int ch = stream.get(); + + while ((ch == ' ' || ch == 9) && !stream.eof()) + { //Skip leading spaces / tabs + ch = stream.get(); + } + + if (!stream.good()) + { + tok = TOKEN_EOF; + return; + } + + //Newline token + if (ch == '\r' || ch == '\n') + { + do + { + ch = stream.get(); + } while ((ch == '\r' || ch == '\n') && !stream.eof()); + + stream.unget(); + + tok = TOKEN_NewLine; + return; + } + + //Open brace token + else if (ch == '{') + { + tok = TOKEN_OpenBrace; + return; + } + + //Close brace token + else if (ch == '}') + { + tok = TOKEN_CloseBrace; + return; + } + + //Text token + if (ch < 32 || ch > 122) //Verify valid char + { + throw std::runtime_error("Parse Error: Invalid character, ConfigLoader::load()"); + } + + tokVal = ""; + tok = TOKEN_Text; + do + { + //Skip comments + if (ch == '/') + { + int ch2 = stream.peek(); + + //C++ style comment (//) + if (ch2 == '/') + { + stream.get(); + do + { + ch = stream.get(); + } while (ch != '\r' && ch != '\n' && !stream.eof()); + + tok = TOKEN_NewLine; + return; + } + } + + //Add valid char to tokVal + tokVal += (char)ch; + + //Next char + ch = stream.get(); + + } while (ch > 32 && ch <= 122 && !stream.eof()); + + stream.unget(); + + return; + } + + void ScriptLoader::_skipNewLines(std::ifstream &stream) + { + while (tok == TOKEN_NewLine) + { + _nextToken(stream); + } + } + + void ScriptLoader::_parseNodes(std::ifstream &stream, ScriptNode *parent) + { + typedef std::pair ScriptItem; + + while (true) + { + switch (tok) + { + //Node + case TOKEN_Text: + { + //Add the new node + ScriptNode *newNode; + if (parent) + { + newNode = parent->addChild(tokVal); + } + else + { + newNode = new ScriptNode(0, tokVal); + } + + //Get values + _nextToken(stream); + std::string valueStr; + int i=0; + while (tok == TOKEN_Text) + { + if (i == 0) + valueStr += tokVal; + else + valueStr += " " + tokVal; + _nextToken(stream); + ++i; + } + newNode->setValue(valueStr); + + //Add root nodes to scriptList + if (!parent) + { + std::string key; + + if (newNode->getValue() == "") + throw std::runtime_error("Root node must have a name (\"" + newNode->getName() + "\")"); + key = newNode->getValue(); + + m_scriptList.insert(ScriptItem(key, newNode)); + } + + _skipNewLines(stream); + + //Add any sub-nodes + if (tok == TOKEN_OpenBrace) + { + //Parse nodes + _nextToken(stream); + _parseNodes(stream, newNode); + //Check for matching closing brace + if (tok != TOKEN_CloseBrace) + { + throw std::runtime_error("Parse Error: Expecting closing brace"); + } + _nextToken(stream); + _skipNewLines(stream); + } + + newNode->m_fileName = m_currentFileName; + + break; + } + + //Out of place brace + case TOKEN_OpenBrace: + throw std::runtime_error("Parse Error: Opening brace out of plane"); + break; + + //Return if end of nodes have been reached + case TOKEN_CloseBrace: + return; + + //Return if reached end of file + case TOKEN_EOF: + return; + + case TOKEN_NewLine: + _nextToken(stream); + break; + } + }; + } + + ScriptNode::ScriptNode(ScriptNode *parent, const std::string &name) + { + m_name = name; + m_parent = parent; + _removeSelf = true; //For proper destruction + m_lastChildFound = -1; + + //Add self to parent's child list (unless this is the root node being created) + if (parent != NULL) + { + m_parent->m_children.push_back(this); + _iter = --(m_parent->m_children.end()); + } + } + + ScriptNode::~ScriptNode() + { + //Delete all children + std::vector::iterator i; + for (i = m_children.begin(); i != m_children.end(); i++) + { + ScriptNode *node = *i; + node->_removeSelf = false; + delete node; + } + m_children.clear(); + + //Remove self from parent's child list + if (_removeSelf && m_parent != NULL) + { + m_parent->m_children.erase(_iter); + } + } + + ScriptNode *ScriptNode::addChild(const std::string &name, bool replaceExisting) + { + if (replaceExisting) + { + ScriptNode *node = findChild(name, false); + if (node) + { + return node; + } + } + return new ScriptNode(this, name); + } + + ScriptNode *ScriptNode::findChild(const std::string &name, bool recursive) + { + int indx, prevC, nextC; + int childCount = (int)m_children.size(); + + if (m_lastChildFound != -1) + { + //If possible, try checking the nodes neighboring the last successful search + //(often nodes searched for in sequence, so this will boost search speeds). + prevC = m_lastChildFound-1; if (prevC < 0) prevC = 0; else if (prevC >= childCount) prevC = childCount-1; + nextC = m_lastChildFound+1; if (nextC < 0) nextC = 0; else if (nextC >= childCount) nextC = childCount-1; + for (indx = prevC; indx <= nextC; ++indx) + { + ScriptNode *node = m_children[indx]; + if (node->m_name == name) + { + m_lastChildFound = indx; + return node; + } + } + + //If not found that way, search for the node from start to finish, avoiding the + //already searched area above. + for (indx = nextC + 1; indx < childCount; ++indx) + { + ScriptNode *node = m_children[indx]; + if (node->m_name == name) { + m_lastChildFound = indx; + return node; + } + } + for (indx = 0; indx < prevC; ++indx) + { + ScriptNode *node = m_children[indx]; + if (node->m_name == name) { + m_lastChildFound = indx; + return node; + } + } + } + else + { + //Search for the node from start to finish + for (indx = 0; indx < childCount; ++indx){ + ScriptNode *node = m_children[indx]; + if (node->m_name == name) { + m_lastChildFound = indx; + return node; + } + } + } + + //If not found, search child nodes (if recursive == true) + if (recursive) + { + for (indx = 0; indx < childCount; ++indx) + { + m_children[indx]->findChild(name, recursive); + } + } + + //Not found anywhere + return NULL; + } + + void ScriptNode::setParent(ScriptNode *newParent) + { + //Remove self from current parent + m_parent->m_children.erase(_iter); + + //Set new parent + m_parent = newParent; + + //Add self to new parent + m_parent->m_children.push_back(this); + _iter = --(m_parent->m_children.end()); + } +} diff --git a/extern/shiny/Main/ScriptLoader.hpp b/extern/shiny/Main/ScriptLoader.hpp new file mode 100644 index 000000000..caf743bd2 --- /dev/null +++ b/extern/shiny/Main/ScriptLoader.hpp @@ -0,0 +1,134 @@ +#ifndef SH_CONFIG_LOADER_H__ +#define SH_CONFIG_LOADER_H__ + +#include +#include +#include +#include + +namespace sh +{ + class ScriptNode; + + /** + * @brief The base class of loaders that read Ogre style script files to get configuration and settings. + * Heavily inspired by: http://www.ogre3d.org/tikiwiki/All-purpose+script+parser + * ( "Non-ogre version") + */ + class ScriptLoader + { + public: + static void loadAllFiles(ScriptLoader* c, const std::string& path); + + ScriptLoader(const std::string& fileEnding); + virtual ~ScriptLoader(); + + std::string m_fileEnding; + + // For a line like + // entity animals/dog + // { + // ... + // } + // The type is "entity" and the name is "animals/dog" + // Or if animal/dog was not there then name is "" + ScriptNode *getConfigScript (const std::string &name); + + std::map getAllConfigScripts (); + + void parseScript(std::ifstream &stream); + + std::string m_currentFileName; + + protected: + + float m_LoadOrder; + // like "*.object" + + std::map m_scriptList; + + enum Token + { + TOKEN_Text, + TOKEN_NewLine, + TOKEN_OpenBrace, + TOKEN_CloseBrace, + TOKEN_EOF + }; + + Token tok, lastTok; + std::string tokVal; + + void _parseNodes(std::ifstream &stream, ScriptNode *parent); + void _nextToken(std::ifstream &stream); + void _skipNewLines(std::ifstream &stream); + + void clearScriptList(); + }; + + class ScriptNode + { + public: + ScriptNode(ScriptNode *parent, const std::string &name = "untitled"); + ~ScriptNode(); + + inline void setName(const std::string &name) + { + this->m_name = name; + } + + inline std::string &getName() + { + return m_name; + } + + inline void setValue(const std::string &value) + { + m_value = value; + } + + inline std::string &getValue() + { + return m_value; + } + + ScriptNode *addChild(const std::string &name = "untitled", bool replaceExisting = false); + ScriptNode *findChild(const std::string &name, bool recursive = false); + + inline std::vector &getChildren() + { + return m_children; + } + + inline ScriptNode *getChild(unsigned int index = 0) + { + assert(index < m_children.size()); + return m_children[index]; + } + + void setParent(ScriptNode *newParent); + + inline ScriptNode *getParent() + { + return m_parent; + } + + std::string m_fileName; + + + private: + std::string m_name; + std::string m_value; + std::vector m_children; + ScriptNode *m_parent; + + + int m_lastChildFound; //The last child node's index found with a call to findChild() + + std::vector::iterator _iter; + bool _removeSelf; + }; + +} + +#endif diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp new file mode 100644 index 000000000..07ef8dfe2 --- /dev/null +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -0,0 +1,707 @@ +#include "ShaderInstance.hpp" + +#include +#include +#include + +#include +#include +#include + +#include + +#include "Preprocessor.hpp" +#include "Factory.hpp" +#include "ShaderSet.hpp" + +namespace +{ + std::string convertLang (sh::Language lang) + { + if (lang == sh::Language_CG) + return "SH_CG"; + else if (lang == sh::Language_HLSL) + return "SH_HLSL"; + else //if (lang == sh::Language_GLSL) + return "SH_GLSL"; + } + + char getComponent(int num) + { + if (num == 0) + return 'x'; + else if (num == 1) + return 'y'; + else if (num == 2) + return 'z'; + else if (num == 3) + return 'w'; + else + throw std::runtime_error("invalid component"); + } + + std::string getFloat(sh::Language lang, int num_components) + { + if (lang == sh::Language_CG || lang == sh::Language_HLSL) + return (num_components == 1) ? "float" : "float" + boost::lexical_cast(num_components); + else + return (num_components == 1) ? "float" : "vec" + boost::lexical_cast(num_components); + } + + bool isCmd (const std::string& source, size_t pos, const std::string& cmd) + { + return (source.size() >= pos + cmd.size() && source.substr(pos, cmd.size()) == cmd); + } + + void writeDebugFile (const std::string& content, const std::string& filename) + { + boost::filesystem::path full_path(boost::filesystem::current_path()); + std::ofstream of ((full_path / filename ).string().c_str() , std::ios_base::out); + of.write(content.c_str(), content.size()); + of.close(); + } +} + +namespace sh +{ + std::string Passthrough::expand_assign(std::string toAssign) + { + std::string res; + + int i = 0; + int current_passthrough = passthrough_number; + int current_component_left = component_start; + int current_component_right = 0; + int components_left = num_components; + int components_at_once; + while (i < num_components) + { + if (components_left + current_component_left <= 4) + components_at_once = components_left; + else + components_at_once = 4 - current_component_left; + + std::string componentStr = "."; + for (int j = 0; j < components_at_once; ++j) + componentStr += getComponent(j + current_component_left); + std::string componentStr2 = "."; + for (int j = 0; j < components_at_once; ++j) + componentStr2 += getComponent(j + current_component_right); + if (num_components == 1) + { + componentStr2 = ""; + } + res += "passthrough" + boost::lexical_cast(current_passthrough) + componentStr + " = " + toAssign + componentStr2; + + current_component_left += components_at_once; + current_component_right += components_at_once; + components_left -= components_at_once; + + i += components_at_once; + + if (components_left == 0) + { + // finished + return res; + } + else + { + // add semicolon to every instruction but the last + res += "; "; + } + + if (current_component_left == 4) + { + current_passthrough++; + current_component_left = 0; + } + } + throw std::runtime_error("expand_assign error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning + } + + std::string Passthrough::expand_receive() + { + std::string res; + + res += getFloat(lang, num_components) + "("; + + int i = 0; + int current_passthrough = passthrough_number; + int current_component = component_start; + int components_left = num_components; + while (i < num_components) + { + int components_at_once = std::min(components_left, 4 - current_component); + + std::string componentStr; + for (int j = 0; j < components_at_once; ++j) + componentStr += getComponent(j + current_component); + + res += "passthrough" + boost::lexical_cast(current_passthrough) + "." + componentStr; + + current_component += components_at_once; + + components_left -= components_at_once; + + i += components_at_once; + + if (components_left == 0) + { + // finished + return res + ")"; +; + } + else + { + // add comma to every variable but the last + res += ", "; + } + + if (current_component == 4) + { + current_passthrough++; + current_component = 0; + } + } + + throw std::runtime_error("expand_receive error"); // this should never happen, but gets us rid of the "control reaches end of non-void function" warning + } + + // ------------------------------------------------------------------------------ + + void ShaderInstance::parse (std::string& source, PropertySetGet* properties) + { + size_t pos = 0; + while (true) + { + pos = source.find("@", pos); + if (pos == std::string::npos) + break; + + if (isCmd(source, pos, "@shProperty")) + { + std::vector args = extractMacroArguments (pos, source); + + size_t start = source.find("(", pos); + size_t end = source.find(")", pos); + std::string cmd = source.substr(pos+1, start-(pos+1)); + + std::string replaceValue; + if (cmd == "shPropertyBool") + { + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + bool val = retrieveValue(value, properties->getContext()).get(); + replaceValue = val ? "1" : "0"; + } + else if (cmd == "shPropertyNotBool") // same as above, but inverts the result + { + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + bool val = retrieveValue(value, properties->getContext()).get(); + replaceValue = val ? "0" : "1"; + } + else if (cmd == "shPropertyString") + { + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + replaceValue = retrieveValue(value, properties->getContext()).get(); + } + else if (cmd == "shPropertyEqual") + { + std::string propertyName = args[0]; + std::string comparedAgainst = args[1]; + std::string value = retrieveValue(properties->getProperty(propertyName), properties->getContext()).get(); + replaceValue = (value == comparedAgainst) ? "1" : "0"; + } + else + throw std::runtime_error ("unknown command \"" + cmd + "\""); + source.replace(pos, (end+1)-pos, replaceValue); + } + else if (isCmd(source, pos, "@shGlobalSetting")) + { + std::vector args = extractMacroArguments (pos, source); + + std::string cmd = source.substr(pos+1, source.find("(", pos)-(pos+1)); + std::string replaceValue; + if (cmd == "shGlobalSettingBool") + { + std::string settingName = args[0]; + std::string value = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); + replaceValue = (value == "true" || value == "1") ? "1" : "0"; + } + else if (cmd == "shGlobalSettingEqual") + { + std::string settingName = args[0]; + std::string comparedAgainst = args[1]; + std::string value = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); + replaceValue = (value == comparedAgainst) ? "1" : "0"; + } + else if (cmd == "shGlobalSettingString") + { + std::string settingName = args[0]; + replaceValue = retrieveValue(mParent->getCurrentGlobalSettings()->getProperty(settingName), NULL).get(); + } + else + throw std::runtime_error ("unknown command \"" + cmd + "\""); + + source.replace(pos, (source.find(")", pos)+1)-pos, replaceValue); + } + else if (isCmd(source, pos, "@shForeach")) + { + + assert(source.find("@shEndForeach", pos) != std::string::npos); + size_t block_end = source.find("@shEndForeach", pos); + + // get the argument for parsing + size_t start = source.find("(", pos); + size_t end = start; + int brace_depth = 1; + while (brace_depth > 0) + { + ++end; + if (source[end] == '(') + ++brace_depth; + else if (source[end] == ')') + --brace_depth; + } + std::string arg = source.substr(start+1, end-(start+1)); + parse(arg, properties); + + int num = boost::lexical_cast(arg); + + // get the content of the inner block + std::string content = source.substr(end+1, block_end - (end+1)); + + // replace both outer and inner block with content of inner block num times + std::string replaceStr; + for (int i=0; i 0) + { + ++_end; + if (addStr[_end] == '(') + ++_brace_depth; + else if (addStr[_end] == ')') + --_brace_depth; + } + std::string arg = addStr.substr(_start+1, _end-(_start+1)); + parse(arg, properties); + + int offset = boost::lexical_cast (arg); + addStr.replace(pos2, (_end+1)-pos2, boost::lexical_cast(i+offset)); + } + else + { + addStr.replace(pos2, std::string("@shIterator").length(), boost::lexical_cast(i)); + } + } + + replaceStr += addStr; + } + source.replace(pos, (block_end+std::string("@shEndForeach").length())-pos, replaceStr); + } + else if (source.size() > pos+1) + ++pos; // skip + } + + } + + ShaderInstance::ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties) + : mName(name) + , mParent(parent) + , mSupported(true) + , mCurrentPassthrough(0) + , mCurrentComponent(0) + { + std::string source = mParent->getSource(); + int type = mParent->getType(); + std::string basePath = mParent->getBasePath(); + size_t pos; + + bool readCache = Factory::getInstance ().getReadSourceCache () && boost::filesystem::exists( + Factory::getInstance ().getCacheFolder () + "/" + mName) + && !mParent->isDirty (); + bool writeCache = Factory::getInstance ().getWriteSourceCache (); + + + if (readCache) + { + std::ifstream ifs( std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str() ); + std::stringstream ss; + ss << ifs.rdbuf(); + source = ss.str(); + } + else + { + std::vector definitions; + + if (mParent->getType() == GPT_Vertex) + definitions.push_back("SH_VERTEX_SHADER"); + else + definitions.push_back("SH_FRAGMENT_SHADER"); + definitions.push_back(convertLang(Factory::getInstance().getCurrentLanguage())); + + parse(source, properties); + + if (Factory::getInstance ().getShaderDebugOutputEnabled ()) + writeDebugFile(source, name + ".pre"); + else + { + #ifdef SHINY_WRITE_SHADER_DEBUG + writeDebugFile(source, name + ".pre"); + #endif + } + + // why do we need our own preprocessor? there are several custom commands available in the shader files + // (for example for binding uniforms to properties or auto constants) - more below. it is important that these + // commands are _only executed if the specific code path actually "survives" the compilation. + // thus, we run the code through a preprocessor first to remove the parts that are unused because of + // unmet #if conditions (or other preprocessor directives). + source = Preprocessor::preprocess(source, basePath, definitions, name); + + // parse counter + std::map counters; + while (true) + { + pos = source.find("@shCounter"); + if (pos == std::string::npos) + break; + + size_t end = source.find(")", pos); + + std::vector args = extractMacroArguments (pos, source); + assert(args.size()); + + int index = boost::lexical_cast(args[0]); + + if (counters.find(index) == counters.end()) + counters[index] = 0; + + source.replace(pos, (end+1)-pos, boost::lexical_cast(counters[index]++)); + } + + // parse passthrough declarations + while (true) + { + pos = source.find("@shAllocatePassthrough"); + if (pos == std::string::npos) + break; + + if (mCurrentPassthrough > 7) + throw std::runtime_error ("too many passthrough's requested (max 8)"); + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() == 2); + + size_t end = source.find(")", pos); + + Passthrough passthrough; + + passthrough.num_components = boost::lexical_cast(args[0]); + assert (passthrough.num_components != 0); + + std::string passthroughName = args[1]; + passthrough.lang = Factory::getInstance().getCurrentLanguage (); + passthrough.component_start = mCurrentComponent; + passthrough.passthrough_number = mCurrentPassthrough; + + mPassthroughMap[passthroughName] = passthrough; + + mCurrentComponent += passthrough.num_components; + if (mCurrentComponent > 3) + { + mCurrentComponent -= 4; + ++mCurrentPassthrough; + } + + source.erase(pos, (end+1)-pos); + } + + // passthrough assign + while (true) + { + pos = source.find("@shPassthroughAssign"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() == 2); + + size_t end = source.find(")", pos); + + std::string passthroughName = args[0]; + std::string assignTo = args[1]; + + assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end()); + Passthrough& p = mPassthroughMap[passthroughName]; + + source.replace(pos, (end+1)-pos, p.expand_assign(assignTo)); + } + + // passthrough receive + while (true) + { + pos = source.find("@shPassthroughReceive"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() == 1); + + size_t end = source.find(")", pos); + std::string passthroughName = args[0]; + + assert(mPassthroughMap.find(passthroughName) != mPassthroughMap.end()); + Passthrough& p = mPassthroughMap[passthroughName]; + + source.replace(pos, (end+1)-pos, p.expand_receive()); + } + + // passthrough vertex outputs + while (true) + { + pos = source.find("@shPassthroughVertexOutputs"); + if (pos == std::string::npos) + break; + + std::string result; + for (int i = 0; i < mCurrentPassthrough+1; ++i) + { + // not using newlines here, otherwise the line numbers reported by compiler would be messed up.. + if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL) + result += ", out float4 passthrough" + boost::lexical_cast(i) + " : TEXCOORD" + boost::lexical_cast(i); + + /* + else + result += "out vec4 passthrough" + boost::lexical_cast(i) + "; "; + */ + else + result += "varying vec4 passthrough" + boost::lexical_cast(i) + "; "; + } + + source.replace(pos, std::string("@shPassthroughVertexOutputs").length(), result); + } + + // passthrough fragment inputs + while (true) + { + pos = source.find("@shPassthroughFragmentInputs"); + if (pos == std::string::npos) + break; + + std::string result; + for (int i = 0; i < mCurrentPassthrough+1; ++i) + { + // not using newlines here, otherwise the line numbers reported by compiler would be messed up.. + if (Factory::getInstance().getCurrentLanguage () == Language_CG || Factory::getInstance().getCurrentLanguage () == Language_HLSL) + result += ", in float4 passthrough" + boost::lexical_cast(i) + " : TEXCOORD" + boost::lexical_cast(i); + /* + else + result += "in vec4 passthrough" + boost::lexical_cast(i) + "; "; + */ + else + result += "varying vec4 passthrough" + boost::lexical_cast(i) + "; "; + } + + source.replace(pos, std::string("@shPassthroughFragmentInputs").length(), result); + } + } + + // save to cache _here_ - we want to preserve some macros + if (writeCache && !readCache) + { + std::ofstream of (std::string(Factory::getInstance ().getCacheFolder () + "/" + mName).c_str(), std::ios_base::out); + of.write(source.c_str(), source.size()); + of.close(); + } + + + // parse shared parameters + while (true) + { + pos = source.find("@shSharedParameter"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size()); + + size_t end = source.find(")", pos); + + mSharedParameters.push_back(args[0]); + + source.erase(pos, (end+1)-pos); + } + + // parse auto constants + typedef std::map< std::string, std::pair > AutoConstantMap; + AutoConstantMap autoConstants; + while (true) + { + pos = source.find("@shAutoConstant"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() >= 2); + + size_t end = source.find(")", pos); + + std::string autoConstantName, uniformName; + std::string extraData; + + uniformName = args[0]; + autoConstantName = args[1]; + if (args.size() > 2) + extraData = args[2]; + + autoConstants[uniformName] = std::make_pair(autoConstantName, extraData); + + source.erase(pos, (end+1)-pos); + } + + // parse uniform properties + while (true) + { + pos = source.find("@shUniformProperty"); + if (pos == std::string::npos) + break; + + std::vector args = extractMacroArguments (pos, source); + assert(args.size() == 2); + + size_t start = source.find("(", pos); + size_t end = source.find(")", pos); + std::string cmd = source.substr(pos, start-pos); + + ValueType vt; + if (cmd == "@shUniformProperty4f") + vt = VT_Vector4; + else if (cmd == "@shUniformProperty3f") + vt = VT_Vector3; + else if (cmd == "@shUniformProperty2f") + vt = VT_Vector2; + else if (cmd == "@shUniformProperty1f") + vt = VT_Float; + else if (cmd == "@shUniformPropertyInt") + vt = VT_Int; + else + throw std::runtime_error ("unsupported command \"" + cmd + "\""); + + + std::string propertyName, uniformName; + uniformName = args[0]; + propertyName = args[1]; + mUniformProperties[uniformName] = std::make_pair(propertyName, vt); + + source.erase(pos, (end+1)-pos); + } + + // parse texture samplers used + while (true) + { + pos = source.find("@shUseSampler"); + if (pos == std::string::npos) + break; + + size_t end = source.find(")", pos); + + mUsedSamplers.push_back(extractMacroArguments (pos, source)[0]); + source.erase(pos, (end+1)-pos); + } + + // convert any left-over @'s to # + boost::algorithm::replace_all(source, "@", "#"); + + Platform* platform = Factory::getInstance().getPlatform(); + + std::string profile; + if (Factory::getInstance ().getCurrentLanguage () == Language_CG) + profile = mParent->getCgProfile (); + else if (Factory::getInstance ().getCurrentLanguage () == Language_HLSL) + profile = mParent->getHlslProfile (); + + + if (type == GPT_Vertex) + mProgram = boost::shared_ptr(platform->createGpuProgram(GPT_Vertex, "", mName, profile, source, Factory::getInstance().getCurrentLanguage())); + else if (type == GPT_Fragment) + mProgram = boost::shared_ptr(platform->createGpuProgram(GPT_Fragment, "", mName, profile, source, Factory::getInstance().getCurrentLanguage())); + + + if (Factory::getInstance ().getShaderDebugOutputEnabled ()) + writeDebugFile(source, name); + else + { +#ifdef SHINY_WRITE_SHADER_DEBUG + writeDebugFile(source, name); +#endif + } + + if (!mProgram->getSupported()) + { + std::cerr << " Full source code below: \n" << source << std::endl; + mSupported = false; + return; + } + + // set auto constants + for (AutoConstantMap::iterator it = autoConstants.begin(); it != autoConstants.end(); ++it) + { + mProgram->setAutoConstant(it->first, it->second.first, it->second.second); + } + } + + std::string ShaderInstance::getName () + { + return mName; + } + + bool ShaderInstance::getSupported () const + { + return mSupported; + } + + std::vector ShaderInstance::getUsedSamplers() + { + return mUsedSamplers; + } + + void ShaderInstance::setUniformParameters (boost::shared_ptr pass, PropertySetGet* properties) + { + for (UniformMap::iterator it = mUniformProperties.begin(); it != mUniformProperties.end(); ++it) + { + pass->setGpuConstant(mParent->getType(), it->first, it->second.second, properties->getProperty(it->second.first), properties->getContext()); + } + } + + std::vector ShaderInstance::extractMacroArguments (size_t pos, const std::string& source) + { + size_t start = source.find("(", pos); + size_t end = source.find(")", pos); + std::string args = source.substr(start+1, end-(start+1)); + std::vector results; + boost::algorithm::split(results, args, boost::is_any_of(",")); + std::for_each(results.begin(), results.end(), + boost::bind(&boost::trim, + _1, std::locale() )); + return results; + } +} diff --git a/extern/shiny/Main/ShaderInstance.hpp b/extern/shiny/Main/ShaderInstance.hpp new file mode 100644 index 000000000..76326ce0c --- /dev/null +++ b/extern/shiny/Main/ShaderInstance.hpp @@ -0,0 +1,71 @@ +#ifndef SH_SHADERINSTANCE_H +#define SH_SHADERINSTANCE_H + +#include + +#include "Platform.hpp" + +namespace sh +{ + class ShaderSet; + + typedef std::map< std::string, std::pair > UniformMap; + + struct Passthrough + { + Language lang; ///< language to generate for + + int num_components; ///< e.g. 4 for a float4 + + int passthrough_number; + int component_start; ///< 0 = x + + std::string expand_assign(std::string assignTo); + std::string expand_receive(); + }; + typedef std::map PassthroughMap; + + /** + * @brief A specific instance of a \a ShaderSet with a deterministic shader source + */ + class ShaderInstance + { + public: + ShaderInstance (ShaderSet* parent, const std::string& name, PropertySetGet* properties); + + std::string getName(); + + bool getSupported () const; + + std::vector getUsedSamplers(); + std::vector getSharedParameters() { return mSharedParameters; } + + void setUniformParameters (boost::shared_ptr pass, PropertySetGet* properties); + + private: + boost::shared_ptr mProgram; + std::string mName; + ShaderSet* mParent; + bool mSupported; ///< shader compilation was sucessful? + + std::vector mUsedSamplers; + ///< names of the texture samplers that are used by this shader + + std::vector mSharedParameters; + + UniformMap mUniformProperties; + ///< uniforms that this depends on, and their property names / value-types + /// @note this lists shared uniform parameters as well + + int mCurrentPassthrough; ///< 0 - x + int mCurrentComponent; ///< 0:x, 1:y, 2:z, 3:w + + PassthroughMap mPassthroughMap; + + std::vector extractMacroArguments (size_t pos, const std::string& source); ///< take a macro invocation and return vector of arguments + + void parse (std::string& source, PropertySetGet* properties); + }; +} + +#endif diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp new file mode 100644 index 000000000..2702ece19 --- /dev/null +++ b/extern/shiny/Main/ShaderSet.cpp @@ -0,0 +1,172 @@ +#include "ShaderSet.hpp" + +#include +#include + +#include +#include +#include + +#include "Factory.hpp" + +namespace sh +{ + ShaderSet::ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, + const std::string& name, PropertySetGet* globalSettingsPtr) + : mBasePath(basePath) + , mName(name) + , mCgProfile(cgProfile) + , mHlslProfile(hlslProfile) + , mIsDirty(false) + { + if (type == "vertex") + mType = GPT_Vertex; + else // if (type == "fragment") + mType = GPT_Fragment; + + std::ifstream stream(sourceFile.c_str(), std::ifstream::in); + std::stringstream buffer; + + buffer << stream.rdbuf(); + stream.close(); + mSource = buffer.str(); + parse(); + } + + void ShaderSet::parse() + { + std::string currentToken; + bool tokenIsRecognized = false; + bool isInBraces = false; + for (std::string::const_iterator it = mSource.begin(); it != mSource.end(); ++it) + { + char c = *it; + if (((c == ' ') && !isInBraces) || (c == '\n') || + ( ((c == '(') || (c == ')')) + && !tokenIsRecognized)) + { + if (tokenIsRecognized) + { + if (boost::starts_with(currentToken, "@shGlobalSetting")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); + size_t start = currentToken.find('(')+1; + mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start)); + } + else if (boost::starts_with(currentToken, "@shPropertyEqual")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos) + && (currentToken.find(',') != std::string::npos)); + size_t start = currentToken.find('(')+1; + size_t end = currentToken.find(','); + mProperties.push_back(currentToken.substr(start, end-start)); + } + else if (boost::starts_with(currentToken, "@shProperty")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); + size_t start = currentToken.find('(')+1; + std::string propertyName = currentToken.substr(start, currentToken.find(')')-start); + // if the property name is constructed dynamically (e.g. through an iterator) then there is nothing we can do + if (propertyName.find("@") == std::string::npos) + mProperties.push_back(propertyName); + } + } + + currentToken = ""; + } + else + { + if (currentToken == "") + { + if (c == '@') + tokenIsRecognized = true; + else + tokenIsRecognized = false; + } + else + { + if (c == '@') + { + // ouch, there are nested macros + // ( for example @shForeach(@shPropertyString(foobar)) ) + currentToken = ""; + } + } + + if (c == '(' && tokenIsRecognized) + isInBraces = true; + else if (c == ')' && tokenIsRecognized) + isInBraces = false; + + currentToken += c; + + } + } + } + + ShaderInstance* ShaderSet::getInstance (PropertySetGet* properties) + { + size_t h = buildHash (properties); + if (std::find(mFailedToCompile.begin(), mFailedToCompile.end(), h) != mFailedToCompile.end()) + return NULL; + if (mInstances.find(h) == mInstances.end()) + { + ShaderInstance newInstance(this, mName + "_" + boost::lexical_cast(h), properties); + if (!newInstance.getSupported()) + { + mFailedToCompile.push_back(h); + return NULL; + } + mInstances.insert(std::make_pair(h, newInstance)); + } + return &mInstances.find(h)->second; + } + + size_t ShaderSet::buildHash (PropertySetGet* properties) + { + size_t seed = 0; + PropertySetGet* currentGlobalSettings = getCurrentGlobalSettings (); + + for (std::vector::iterator it = mProperties.begin(); it != mProperties.end(); ++it) + { + std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); + boost::hash_combine(seed, v); + } + for (std::vector ::iterator it = mGlobalSettings.begin(); it != mGlobalSettings.end(); ++it) + { + boost::hash_combine(seed, retrieveValue(currentGlobalSettings->getProperty(*it), NULL).get()); + } + boost::hash_combine(seed, static_cast(Factory::getInstance().getCurrentLanguage())); + return seed; + } + + PropertySetGet* ShaderSet::getCurrentGlobalSettings() const + { + return Factory::getInstance ().getCurrentGlobalSettings (); + } + + std::string ShaderSet::getBasePath() const + { + return mBasePath; + } + + std::string ShaderSet::getSource() const + { + return mSource; + } + + std::string ShaderSet::getCgProfile() const + { + return mCgProfile; + } + + std::string ShaderSet::getHlslProfile() const + { + return mHlslProfile; + } + + int ShaderSet::getType() const + { + return mType; + } +} diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp new file mode 100644 index 000000000..776750598 --- /dev/null +++ b/extern/shiny/Main/ShaderSet.hpp @@ -0,0 +1,71 @@ +#ifndef SH_SHADERSET_H +#define SH_SHADERSET_H + +#include +#include +#include + +#include "ShaderInstance.hpp" + +namespace sh +{ + class PropertySetGet; + + typedef std::map ShaderInstanceMap; + + /** + * @brief Contains possible shader permutations of a single uber-shader (represented by one source file) + */ + class ShaderSet + { + public: + ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, + const std::string& name, PropertySetGet* globalSettingsPtr); + + /// Retrieve a shader instance for the given properties. \n + /// If a \a ShaderInstance with the same properties exists already, simply returns this instance. \n + /// Otherwise, creates a new \a ShaderInstance (i.e. compiles a new shader). \n + /// Might also return NULL if the shader failed to compile. \n + /// @note Only the properties that actually affect the shader source are taken into consideration here, + /// so it does not matter if you pass any extra properties that the shader does not care about. + ShaderInstance* getInstance (PropertySetGet* properties); + + void markDirty() { mIsDirty = true; } + ///< Signals that the cache is out of date, and thus should not be used this time + + private: + PropertySetGet* getCurrentGlobalSettings() const; + std::string getBasePath() const; + std::string getSource() const; + std::string getCgProfile() const; + std::string getHlslProfile() const; + int getType() const; + + bool isDirty() { return mIsDirty; } + + friend class ShaderInstance; + + bool mIsDirty; + + private: + GpuProgramType mType; + std::string mSource; + std::string mBasePath; + std::string mCgProfile; + std::string mHlslProfile; + std::string mName; + + std::vector mFailedToCompile; + + std::vector mGlobalSettings; ///< names of the global settings that affect the shader source + std::vector mProperties; ///< names of the per-material properties that affect the shader source + + ShaderInstanceMap mInstances; ///< maps permutation ID (generated from the properties) to \a ShaderInstance + + void parse(); ///< find out which properties and global settings affect the shader source + + size_t buildHash (PropertySetGet* properties); + }; +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp b/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp new file mode 100644 index 000000000..fe5aa2fe7 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreGpuProgram.cpp @@ -0,0 +1,70 @@ +#include + +#include "OgreGpuProgram.hpp" + +#include + +#include +#include +#include + +namespace sh +{ + OgreGpuProgram::OgreGpuProgram( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, const std::string& lang, + const std::string& resourceGroup) + : GpuProgram() + { + Ogre::HighLevelGpuProgramManager& mgr = Ogre::HighLevelGpuProgramManager::getSingleton(); + assert (mgr.getByName(name).isNull() && "Vertex program already exists"); + + Ogre::GpuProgramType t; + if (type == GPT_Vertex) + t = Ogre::GPT_VERTEX_PROGRAM; + else + t = Ogre::GPT_FRAGMENT_PROGRAM; + + mProgram = mgr.createProgram(name, resourceGroup, lang, t); + if (lang != "glsl") + mProgram->setParameter("entry_point", "main"); + + if (lang == "hlsl") + mProgram->setParameter("target", profile); + else if (lang == "cg") + mProgram->setParameter("profiles", profile); + + mProgram->setSource(source); + mProgram->load(); + + if (mProgram.isNull() || !mProgram->isSupported()) + std::cerr << "Failed to compile shader \"" << name << "\". Consider the OGRE log for more information." << std::endl; + } + + bool OgreGpuProgram::getSupported() + { + return (!mProgram.isNull() && mProgram->isSupported()); + } + + void OgreGpuProgram::setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo) + { + assert (!mProgram.isNull() && mProgram->isSupported()); + const Ogre::GpuProgramParameters::AutoConstantDefinition* d = Ogre::GpuProgramParameters::getAutoConstantDefinition(autoConstantName); + + if (!d) + throw std::runtime_error ("can't find auto constant with name \"" + autoConstantName + "\""); + Ogre::GpuProgramParameters::AutoConstantType t = d->acType; + + // this simplifies debugging for CG a lot. + mProgram->getDefaultParameters()->setIgnoreMissingParams(true); + + if (d->dataType == Ogre::GpuProgramParameters::ACDT_NONE) + mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, 0); + else if (d->dataType == Ogre::GpuProgramParameters::ACDT_INT) + mProgram->getDefaultParameters()->setNamedAutoConstant (name, t, extraInfo == "" ? 0 : boost::lexical_cast(extraInfo)); + else if (d->dataType == Ogre::GpuProgramParameters::ACDT_REAL) + mProgram->getDefaultParameters()->setNamedAutoConstantReal (name, t, extraInfo == "" ? 0.f : boost::lexical_cast(extraInfo)); + } +} diff --git a/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp b/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp new file mode 100644 index 000000000..42673ed9b --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreGpuProgram.hpp @@ -0,0 +1,31 @@ +#ifndef SH_OGREGPUPROGRAM_H +#define SH_OGREGPUPROGRAM_H + +#include + +#include + +#include "../../Main/Platform.hpp" + +namespace sh +{ + class OgreGpuProgram : public GpuProgram + { + public: + OgreGpuProgram ( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, const std::string& lang, + const std::string& resourceGroup); + + virtual bool getSupported(); + + virtual void setAutoConstant (const std::string& name, const std::string& autoConstantName, const std::string& extraInfo = ""); + + private: + Ogre::HighLevelGpuProgramPtr mProgram; + }; +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.cpp b/extern/shiny/Platforms/Ogre/OgreMaterial.cpp new file mode 100644 index 000000000..4a550b8bf --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreMaterial.cpp @@ -0,0 +1,99 @@ +#include "OgreMaterial.hpp" + +#include +#include +#include + +#include "OgrePass.hpp" +#include "OgreMaterialSerializer.hpp" +#include "OgrePlatform.hpp" + +namespace sh +{ + static const std::string sDefaultTechniqueName = "SH_DefaultTechnique"; + + OgreMaterial::OgreMaterial (const std::string& name, const std::string& resourceGroup) + : Material() + { + assert (Ogre::MaterialManager::getSingleton().getByName(name).isNull() && "Material already exists"); + mMaterial = Ogre::MaterialManager::getSingleton().create (name, resourceGroup); + mMaterial->removeAllTechniques(); + mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); + mMaterial->compile(); + } + + OgreMaterial::~OgreMaterial() + { + Ogre::MaterialManager::getSingleton().remove(mMaterial->getName()); + } + + boost::shared_ptr OgreMaterial::createPass (const std::string& configuration, unsigned short lodIndex) + { + return boost::shared_ptr (new OgrePass (this, configuration, lodIndex)); + } + + void OgreMaterial::removeAll () + { + mMaterial->removeAllTechniques(); + mMaterial->createTechnique()->setSchemeName (sDefaultTechniqueName); + mMaterial->compile(); + } + + void OgreMaterial::setLodLevels (const std::string& lodLevels) + { + OgreMaterialSerializer& s = OgrePlatform::getSerializer(); + + s.setMaterialProperty ("lod_values", lodLevels, mMaterial); + } + + bool OgreMaterial::createConfiguration (const std::string& name, unsigned short lodIndex) + { + for (int i=0; igetNumTechniques(); ++i) + { + if (mMaterial->getTechnique(i)->getSchemeName() == name && mMaterial->getTechnique(i)->getLodIndex() == lodIndex) + return false; + } + + Ogre::Technique* t = mMaterial->createTechnique(); + t->setSchemeName (name); + t->setLodIndex (lodIndex); + if (mShadowCasterMaterial != "") + t->setShadowCasterMaterial(mShadowCasterMaterial); + + mMaterial->compile(); + + return true; + } + + Ogre::MaterialPtr OgreMaterial::getOgreMaterial () + { + return mMaterial; + } + + Ogre::Technique* OgreMaterial::getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex) + { + for (int i=0; igetNumTechniques(); ++i) + { + if (mMaterial->getTechnique(i)->getSchemeName() == configurationName && mMaterial->getTechnique(i)->getLodIndex() == lodIndex) + { + return mMaterial->getTechnique(i); + } + } + + // Prepare and throw error message + std::stringstream message; + message << "Could not find configurationName '" << configurationName + << "' and lodIndex " << lodIndex; + + throw std::runtime_error(message.str()); + } + + void OgreMaterial::setShadowCasterMaterial (const std::string& name) + { + mShadowCasterMaterial = name; + for (int i=0; igetNumTechniques(); ++i) + { + mMaterial->getTechnique(i)->setShadowCasterMaterial(mShadowCasterMaterial); + } + } +} diff --git a/extern/shiny/Platforms/Ogre/OgreMaterial.hpp b/extern/shiny/Platforms/Ogre/OgreMaterial.hpp new file mode 100644 index 000000000..bec23f0b6 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreMaterial.hpp @@ -0,0 +1,38 @@ +#ifndef SH_OGREMATERIAL_H +#define SH_OGREMATERIAL_H + +#include + +#include + +#include "../../Main/Platform.hpp" + +namespace sh +{ + class OgreMaterial : public Material + { + public: + OgreMaterial (const std::string& name, const std::string& resourceGroup); + virtual ~OgreMaterial(); + + virtual boost::shared_ptr createPass (const std::string& configuration, unsigned short lodIndex); + virtual bool createConfiguration (const std::string& name, unsigned short lodIndex); + + virtual void removeAll (); + + Ogre::MaterialPtr getOgreMaterial(); + + virtual void setLodLevels (const std::string& lodLevels); + + Ogre::Technique* getOgreTechniqueForConfiguration (const std::string& configurationName, unsigned short lodIndex = 0); + + virtual void setShadowCasterMaterial (const std::string& name); + + private: + Ogre::MaterialPtr mMaterial; + + std::string mShadowCasterMaterial; + }; +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp new file mode 100644 index 000000000..9f57c7b44 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp @@ -0,0 +1,67 @@ +#include "OgreMaterialSerializer.hpp" + +namespace sh +{ + void OgreMaterialSerializer::reset() + { + mScriptContext.section = Ogre::MSS_NONE; + mScriptContext.material.setNull(); + mScriptContext.technique = 0; + mScriptContext.pass = 0; + mScriptContext.textureUnit = 0; + mScriptContext.program.setNull(); + mScriptContext.lineNo = 0; + mScriptContext.filename.clear(); + mScriptContext.techLev = -1; + mScriptContext.passLev = -1; + mScriptContext.stateLev = -1; + } + + bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass) + { + reset(); + + mScriptContext.section = Ogre::MSS_PASS; + mScriptContext.pass = pass; + + if (mPassAttribParsers.find (param) == mPassAttribParsers.end()) + return false; + else + { + mPassAttribParsers.find(param)->second(value, mScriptContext); + return true; + } + } + + bool OgreMaterialSerializer::setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t) + { + reset(); + + mScriptContext.section = Ogre::MSS_TEXTUREUNIT; + mScriptContext.textureUnit = t; + + if (mTextureUnitAttribParsers.find (param) == mTextureUnitAttribParsers.end()) + return false; + else + { + mTextureUnitAttribParsers.find(param)->second(value, mScriptContext); + return true; + } + } + + bool OgreMaterialSerializer::setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m) + { + reset(); + + mScriptContext.section = Ogre::MSS_MATERIAL; + mScriptContext.material = m; + + if (mMaterialAttribParsers.find (param) == mMaterialAttribParsers.end()) + return false; + else + { + mMaterialAttribParsers.find(param)->second(value, mScriptContext); + return true; + } + } +} diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp new file mode 100644 index 000000000..acfc5a362 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.hpp @@ -0,0 +1,29 @@ +#ifndef SH_OGREMATERIALSERIALIZER_H +#define SH_OGREMATERIALSERIALIZER_H + +#include + +namespace Ogre +{ + class Pass; +} + +namespace sh +{ + /** + * @brief This class allows me to let Ogre handle the pass & texture unit properties + */ + class OgreMaterialSerializer : public Ogre::MaterialSerializer + { + public: + bool setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass); + bool setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t); + bool setMaterialProperty (const std::string& param, std::string value, Ogre::MaterialPtr m); + + private: + void reset(); + }; + +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp new file mode 100644 index 000000000..8cfaae078 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgrePass.cpp @@ -0,0 +1,128 @@ +#include + +#include "OgrePass.hpp" + +#include +#include + +#include "OgreTextureUnitState.hpp" +#include "OgreGpuProgram.hpp" +#include "OgreMaterial.hpp" +#include "OgreMaterialSerializer.hpp" +#include "OgrePlatform.hpp" + +namespace sh +{ + OgrePass::OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex) + : Pass() + { + Ogre::Technique* t = parent->getOgreTechniqueForConfiguration(configuration, lodIndex); + mPass = t->createPass(); + } + + boost::shared_ptr OgrePass::createTextureUnitState () + { + return boost::shared_ptr (new OgreTextureUnitState (this)); + } + + void OgrePass::assignProgram (GpuProgramType type, const std::string& name) + { + if (type == GPT_Vertex) + mPass->setVertexProgram (name); + else if (type == GPT_Fragment) + mPass->setFragmentProgram (name); + else + throw std::runtime_error("unsupported GpuProgramType"); + } + + Ogre::Pass* OgrePass::getOgrePass () + { + return mPass; + } + + bool OgrePass::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) + { + if (((typeid(*value) == typeid(StringValue)) || typeid(*value) == typeid(LinkedValue)) + && retrieveValue(value, context).get() == "default") + return true; + + if (name == "vertex_program") + return true; // handled already + else if (name == "fragment_program") + return true; // handled already + else if (name == "ffp_vertex_colour_ambient") + { + bool enabled = retrieveValue(value, context).get(); + // fixed-function vertex colour tracking + mPass->setVertexColourTracking(enabled ? Ogre::TVC_AMBIENT : Ogre::TVC_NONE); + return true; + } + else + { + OgreMaterialSerializer& s = OgrePlatform::getSerializer(); + + return s.setPassProperty (name, retrieveValue(value, context).get(), mPass); + } + } + + void OgrePass::setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context) + { + Ogre::GpuProgramParametersSharedPtr params; + if (type == GPT_Vertex) + { + if (!mPass->hasVertexProgram ()) + return; + params = mPass->getVertexProgramParameters(); + } + else if (type == GPT_Fragment) + { + if (!mPass->hasFragmentProgram ()) + return; + params = mPass->getFragmentProgramParameters(); + } + + if (vt == VT_Float) + params->setNamedConstant (name, retrieveValue(value, context).get()); + else if (vt == VT_Int) + params->setNamedConstant (name, retrieveValue(value, context).get()); + else if (vt == VT_Vector4) + { + Vector4 v = retrieveValue(value, context); + params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, v.mW)); + } + else if (vt == VT_Vector3) + { + Vector3 v = retrieveValue(value, context); + params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, v.mZ, 1.0)); + } + else if (vt == VT_Vector2) + { + Vector2 v = retrieveValue(value, context); + params->setNamedConstant (name, Ogre::Vector4(v.mX, v.mY, 1.0, 1.0)); + } + else + throw std::runtime_error ("unsupported constant type"); + } + + void OgrePass::addSharedParameter (int type, const std::string& name) + { + Ogre::GpuProgramParametersSharedPtr params; + if (type == GPT_Vertex) + params = mPass->getVertexProgramParameters(); + else if (type == GPT_Fragment) + params = mPass->getFragmentProgramParameters(); + + params->addSharedParameters (name); + } + + void OgrePass::setTextureUnitIndex (int programType, const std::string& name, int index) + { + Ogre::GpuProgramParametersSharedPtr params; + if (programType == GPT_Vertex) + params = mPass->getVertexProgramParameters(); + else if (programType == GPT_Fragment) + params = mPass->getFragmentProgramParameters(); + + params->setNamedConstant(name, index); + } +} diff --git a/extern/shiny/Platforms/Ogre/OgrePass.hpp b/extern/shiny/Platforms/Ogre/OgrePass.hpp new file mode 100644 index 000000000..da67a1a2a --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgrePass.hpp @@ -0,0 +1,35 @@ +#ifndef SH_OGREPASS_H +#define SH_OGREPASS_H + +#include + +#include "../../Main/Platform.hpp" + +namespace sh +{ + class OgreMaterial; + + class OgrePass : public Pass + { + public: + OgrePass (OgreMaterial* parent, const std::string& configuration, unsigned short lodIndex); + + virtual boost::shared_ptr createTextureUnitState (); + virtual void assignProgram (GpuProgramType type, const std::string& name); + + Ogre::Pass* getOgrePass(); + + virtual void setGpuConstant (int type, const std::string& name, ValueType vt, PropertyValuePtr value, PropertySetGet* context); + + virtual void addSharedParameter (int type, const std::string& name); + virtual void setTextureUnitIndex (int programType, const std::string& name, int index); + + private: + Ogre::Pass* mPass; + + protected: + virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context); + }; +} + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp new file mode 100644 index 000000000..357949402 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp @@ -0,0 +1,174 @@ +#include + +#include "OgrePlatform.hpp" + +#include +#include +#include + +#include "OgreMaterial.hpp" +#include "OgreGpuProgram.hpp" +#include "OgreMaterialSerializer.hpp" + +#include "../../Main/MaterialInstance.hpp" +#include "../../Main/Factory.hpp" + +namespace +{ + std::string convertLang (sh::Language lang) + { + if (lang == sh::Language_CG) + return "cg"; + else if (lang == sh::Language_HLSL) + return "hlsl"; + else if (lang == sh::Language_GLSL) + return "glsl"; + throw std::runtime_error ("invalid language, valid are: cg, hlsl, glsl"); + } +} + +namespace sh +{ + OgreMaterialSerializer* OgrePlatform::sSerializer = 0; + + OgrePlatform::OgrePlatform(const std::string& resourceGroupName, const std::string& basePath) + : Platform(basePath) + , mResourceGroup(resourceGroupName) + { + Ogre::MaterialManager::getSingleton().addListener(this); + + if (supportsShaderSerialization()) + Ogre::GpuProgramManager::getSingletonPtr()->setSaveMicrocodesToCache(true); + + sSerializer = new OgreMaterialSerializer(); + } + + OgreMaterialSerializer& OgrePlatform::getSerializer() + { + assert(sSerializer); + return *sSerializer; + } + + OgrePlatform::~OgrePlatform () + { + delete sSerializer; + } + + bool OgrePlatform::isProfileSupported (const std::string& profile) + { + return Ogre::GpuProgramManager::getSingleton().isSyntaxSupported(profile); + } + + bool OgrePlatform::supportsShaderSerialization () + { + // Not very reliable in OpenGL mode (requires extension), and somehow doesn't work on linux even if the extension is present + return Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") == std::string::npos; + } + + bool OgrePlatform::supportsMaterialQueuedListener () + { + return true; + } + + boost::shared_ptr OgrePlatform::createMaterial (const std::string& name) + { + OgreMaterial* material = new OgreMaterial(name, mResourceGroup); + return boost::shared_ptr (material); + } + + boost::shared_ptr OgrePlatform::createGpuProgram ( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, Language lang) + { + OgreGpuProgram* prog = new OgreGpuProgram (type, compileArguments, name, profile, source, convertLang(lang), mResourceGroup); + return boost::shared_ptr (static_cast(prog)); + } + + Ogre::Technique* OgrePlatform::handleSchemeNotFound ( + unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, + unsigned short lodIndex, const Ogre::Renderable *rend) + { + MaterialInstance* m = fireMaterialRequested(originalMaterial->getName(), schemeName, lodIndex); + if (m) + { + OgreMaterial* _m = static_cast(m->getMaterial()); + return _m->getOgreTechniqueForConfiguration (schemeName, lodIndex); + } + else + return 0; // material does not belong to us + } + + void OgrePlatform::serializeShaders (const std::string& file) + { + std::fstream output; + output.open(file.c_str(), std::ios::out | std::ios::binary); + Ogre::DataStreamPtr shaderCache (OGRE_NEW Ogre::FileStreamDataStream(file, &output, false)); + Ogre::GpuProgramManager::getSingleton().saveMicrocodeCache(shaderCache); + } + + void OgrePlatform::deserializeShaders (const std::string& file) + { + std::ifstream inp; + inp.open(file.c_str(), std::ios::in | std::ios::binary); + Ogre::DataStreamPtr shaderCache(OGRE_NEW Ogre::FileStreamDataStream(file, &inp, false)); + Ogre::GpuProgramManager::getSingleton().loadMicrocodeCache(shaderCache); + } + + void OgrePlatform::setSharedParameter (const std::string& name, PropertyValuePtr value) + { + Ogre::GpuSharedParametersPtr params; + if (mSharedParameters.find(name) == mSharedParameters.end()) + { + params = Ogre::GpuProgramManager::getSingleton().createSharedParameters(name); + Ogre::GpuConstantType type; + if (typeid(*value) == typeid(Vector4)) + type = Ogre::GCT_FLOAT4; + else if (typeid(*value) == typeid(Vector3)) + type = Ogre::GCT_FLOAT3; + else if (typeid(*value) == typeid(Vector2)) + type = Ogre::GCT_FLOAT2; + else if (typeid(*value) == typeid(FloatValue)) + type = Ogre::GCT_FLOAT1; + else if (typeid(*value) == typeid(IntValue)) + type = Ogre::GCT_INT1; + else + assert(0); + params->addConstantDefinition(name, type); + mSharedParameters[name] = params; + } + else + params = mSharedParameters.find(name)->second; + + Ogre::Vector4 v (1.0, 1.0, 1.0, 1.0); + if (typeid(*value) == typeid(Vector4)) + { + Vector4 vec = retrieveValue(value, NULL); + v.x = vec.mX; + v.y = vec.mY; + v.z = vec.mZ; + v.w = vec.mW; + } + else if (typeid(*value) == typeid(Vector3)) + { + Vector3 vec = retrieveValue(value, NULL); + v.x = vec.mX; + v.y = vec.mY; + v.z = vec.mZ; + } + else if (typeid(*value) == typeid(Vector2)) + { + Vector2 vec = retrieveValue(value, NULL); + v.x = vec.mX; + v.y = vec.mY; + } + else if (typeid(*value) == typeid(FloatValue)) + v.x = retrieveValue(value, NULL).get(); + else if (typeid(*value) == typeid(IntValue)) + v.x = static_cast(retrieveValue(value, NULL).get()); + else + throw std::runtime_error ("unsupported property type for shared parameter \"" + name + "\""); + params->setNamedConstant(name, v); + } +} diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.hpp b/extern/shiny/Platforms/Ogre/OgrePlatform.hpp new file mode 100644 index 000000000..d115c46bb --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgrePlatform.hpp @@ -0,0 +1,72 @@ +#ifndef SH_OGREPLATFORM_H +#define SH_OGREPLATFORM_H + +/** + * @addtogroup Platforms + * @{ + */ + +/** + * @addtogroup Ogre + * A set of classes to interact with Ogre's material system + * @{ + */ + +#include "../../Main/Platform.hpp" + +#include +#include + +namespace sh +{ + class OgreMaterialSerializer; + + class OgrePlatform : public Platform, public Ogre::MaterialManager::Listener + { + public: + OgrePlatform (const std::string& resourceGroupName, const std::string& basePath); + virtual ~OgrePlatform (); + + virtual Ogre::Technique* handleSchemeNotFound ( + unsigned short schemeIndex, const Ogre::String &schemeName, Ogre::Material *originalMaterial, + unsigned short lodIndex, const Ogre::Renderable *rend); + + static OgreMaterialSerializer& getSerializer(); + + private: + virtual bool isProfileSupported (const std::string& profile); + + virtual void serializeShaders (const std::string& file); + virtual void deserializeShaders (const std::string& file); + + virtual boost::shared_ptr createMaterial (const std::string& name); + + virtual boost::shared_ptr createGpuProgram ( + GpuProgramType type, + const std::string& compileArguments, + const std::string& name, const std::string& profile, + const std::string& source, Language lang); + + virtual void setSharedParameter (const std::string& name, PropertyValuePtr value); + + friend class ShaderInstance; + friend class Factory; + + protected: + virtual bool supportsShaderSerialization (); + virtual bool supportsMaterialQueuedListener (); + + std::string mResourceGroup; + + static OgreMaterialSerializer* sSerializer; + + std::map mSharedParameters; + }; +} + +/** + * @} + * @} + */ + +#endif diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp new file mode 100644 index 000000000..0938cf667 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.cpp @@ -0,0 +1,40 @@ +#include "OgreTextureUnitState.hpp" + +#include "OgrePass.hpp" +#include "OgrePlatform.hpp" +#include "OgreMaterialSerializer.hpp" + +namespace sh +{ + OgreTextureUnitState::OgreTextureUnitState (OgrePass* parent) + : TextureUnitState() + { + mTextureUnitState = parent->getOgrePass()->createTextureUnitState(""); + } + + bool OgreTextureUnitState::setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context) + { + OgreMaterialSerializer& s = OgrePlatform::getSerializer(); + + if (name == "texture_alias") + { + // texture alias in this library refers to something else than in ogre + // delegate up + return TextureUnitState::setPropertyOverride (name, value, context); + } + else if (name == "direct_texture") + { + setTextureName (retrieveValue(value, context).get()); + return true; + } + else if (name == "create_in_ffp") + return true; // handled elsewhere + + return s.setTextureUnitProperty (name, retrieveValue(value, context).get(), mTextureUnitState); + } + + void OgreTextureUnitState::setTextureName (const std::string& textureName) + { + mTextureUnitState->setTextureName(textureName); + } +} diff --git a/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp new file mode 100644 index 000000000..d36f4b945 --- /dev/null +++ b/extern/shiny/Platforms/Ogre/OgreTextureUnitState.hpp @@ -0,0 +1,27 @@ +#ifndef SH_OGRETEXTUREUNITSTATE_H +#define SH_OGRETEXTUREUNITSTATE_H + +#include + +#include "../../Main/Platform.hpp" + +namespace sh +{ + class OgrePass; + + class OgreTextureUnitState : public TextureUnitState + { + public: + OgreTextureUnitState (OgrePass* parent); + + virtual void setTextureName (const std::string& textureName); + + private: + Ogre::TextureUnitState* mTextureUnitState; + + protected: + virtual bool setPropertyOverride (const std::string &name, PropertyValuePtr& value, PropertySetGet* context); + }; +} + +#endif diff --git a/extern/shiny/Preprocessor/aq.cpp b/extern/shiny/Preprocessor/aq.cpp new file mode 100644 index 000000000..b81d5b332 --- /dev/null +++ b/extern/shiny/Preprocessor/aq.cpp @@ -0,0 +1,236 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001 Daniel C. Nuffer. + Copyright (c) 2001-2011 Hartmut Kaiser. + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include + +#include +#include + +#include // configuration data +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +int aq_grow(aq_queue q) +{ + using namespace std; // some systems have memcpy/realloc in std + std::size_t new_size = q->max_size << 1; + aq_stdelement* new_queue = (aq_stdelement*)realloc(q->queue, + new_size * sizeof(aq_stdelement)); + + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->max_size < 100000); + BOOST_ASSERT(q->size <= q->max_size); + +#define ASSERT_SIZE BOOST_ASSERT( \ + ((q->tail + q->max_size + 1) - q->head) % q->max_size == \ + q->size % q->max_size) + + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + if (!new_queue) + { + BOOST_ASSERT(0); + return 0; + } + + q->queue = new_queue; + if (q->tail <= q->head) /* tail has wrapped around */ + { + /* move the tail from the beginning to the end */ + memcpy(q->queue + q->max_size, q->queue, + (q->tail + 1) * sizeof(aq_stdelement)); + q->tail += q->max_size; + } + q->max_size = new_size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_enqueue(aq_queue q, aq_stdelement e) +{ + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_FULL(q)) + if (!aq_grow(q)) + return 0; + + ++q->tail; + if (q->tail == q->max_size) + q->tail = 0; + + q->queue[q->tail] = e; + ++q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_enqueue_front(aq_queue q, aq_stdelement e) +{ + BOOST_ASSERT(NULL != q); + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_FULL(q)) + if (!aq_grow(q)) + return 0; + + if (q->head == 0) + q->head = q->max_size - 1; + else + --q->head; + + q->queue[q->head] = e; + ++q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +int aq_serve(aq_queue q, aq_stdelement *e) +{ + + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_EMPTY(q)) + return 0; + + *e = q->queue[q->head]; + return aq_pop(q); +} + +int aq_pop(aq_queue q) +{ + + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + + if (AQ_EMPTY(q)) + return 0; + + ++q->head; + if (q->head == q->max_size) + q->head = 0; + --q->size; + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return 1; +} + +aq_queue aq_create(void) +{ + aq_queue q; + + using namespace std; // some systems have malloc in std + q = (aq_queue)malloc(sizeof(aq_queuetype)); + if (!q) + { + return 0; + } + + q->max_size = 8; /* initial size */ + q->queue = (aq_stdelement*)malloc( + sizeof(aq_stdelement) * q->max_size); + if (!q->queue) + { + free(q); + return 0; + } + + q->head = 0; + q->tail = q->max_size - 1; + q->size = 0; + + + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + return q; +} + +void aq_terminate(aq_queue q) +{ + using namespace std; // some systems have free in std + + BOOST_ASSERT(NULL != q); + BOOST_ASSERT(q->size <= q->max_size); + ASSERT_SIZE; + BOOST_ASSERT(q->head <= q->max_size); + BOOST_ASSERT(q->tail <= q->max_size); + + free(q->queue); + free(q); +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + diff --git a/extern/shiny/Preprocessor/cpp_re.cpp b/extern/shiny/Preprocessor/cpp_re.cpp new file mode 100644 index 000000000..69d77c372 --- /dev/null +++ b/extern/shiny/Preprocessor/cpp_re.cpp @@ -0,0 +1,442 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Copyright (c) 2001 Daniel C. Nuffer + Copyright (c) 2001-2011 Hartmut Kaiser. + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + TODO: + It also may be necessary to add $ to identifiers, for asm. + handle errors better. + have some easier way to parse strings instead of files (done) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include + +#include +#include +#include +#include +#include +#include +#include + +#include // configuration data + +#if defined(BOOST_HAS_UNISTD_H) +#include +#else +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +#if defined(BOOST_MSVC) +#pragma warning (disable: 4101) // 'foo' : unreferenced local variable +#pragma warning (disable: 4102) // 'foo' : unreferenced label +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_BSIZE 196608 + +#define YYCTYPE uchar +#define YYCURSOR cursor +#define YYLIMIT limit +#define YYMARKER marker +#define YYFILL(n) \ + { \ + cursor = uchar_wrapper(fill(s, cursor), cursor.column); \ + limit = uchar_wrapper (s->lim); \ + } \ + /**/ + +#include + +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_UPDATE_CURSOR() \ + { \ + s->line += count_backslash_newlines(s, cursor); \ + s->curr_column = cursor.column; \ + s->cur = cursor; \ + s->lim = limit; \ + s->ptr = marker; \ + } \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_WAVE_RET(i) \ + { \ + BOOST_WAVE_UPDATE_CURSOR() \ + if (s->cur > s->lim) \ + return T_EOF; /* may happen for empty files */ \ + return (i); \ + } \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { +namespace cpplexer { +namespace re2clex { + +#define RE2C_ASSERT BOOST_ASSERT + +int get_one_char(Scanner *s) +{ + if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + if (s->act < s->last) + return *(s->act)++; + } + return -1; +} + +std::ptrdiff_t rewind_stream (Scanner *s, int cnt) +{ + if (0 != s->act) { + RE2C_ASSERT(s->first != 0 && s->last != 0); + s->act += cnt; + RE2C_ASSERT(s->first <= s->act && s->act <= s->last); + return s->act - s->first; + } + return 0; +} + +std::size_t get_first_eol_offset(Scanner* s) +{ + if (!AQ_EMPTY(s->eol_offsets)) + { + return s->eol_offsets->queue[s->eol_offsets->head]; + } + else + { + return (unsigned int)-1; + } +} + +void adjust_eol_offsets(Scanner* s, std::size_t adjustment) +{ + aq_queue q; + std::size_t i; + + if (!s->eol_offsets) + s->eol_offsets = aq_create(); + + q = s->eol_offsets; + + if (AQ_EMPTY(q)) + return; + + i = q->head; + while (i != q->tail) + { + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; + ++i; + if (i == q->max_size) + i = 0; + } + if (adjustment > q->queue[i]) + q->queue[i] = 0; + else + q->queue[i] -= adjustment; +} + +int count_backslash_newlines(Scanner *s, uchar *cursor) +{ + std::size_t diff, offset; + int skipped = 0; + + /* figure out how many backslash-newlines skipped over unknowingly. */ + diff = cursor - s->bot; + offset = get_first_eol_offset(s); + while (offset <= diff && offset != (unsigned int)-1) + { + skipped++; + aq_pop(s->eol_offsets); + offset = get_first_eol_offset(s); + } + return skipped; +} + +bool is_backslash(uchar *p, uchar *end, int &len) +{ + if (*p == '\\') { + len = 1; + return true; + } + else if (*p == '?' && *(p+1) == '?' && (p+2 < end && *(p+2) == '/')) { + len = 3; + return true; + } + return false; +} + +uchar *fill(Scanner *s, uchar *cursor) +{ + using namespace std; // some systems have memcpy etc. in namespace std + if(!s->eof) + { + uchar* p; + std::ptrdiff_t cnt = s->tok - s->bot; + if(cnt) + { + if (NULL == s->lim) + s->lim = s->top; + memmove(s->bot, s->tok, s->lim - s->tok); + s->tok = s->cur = s->bot; + s->ptr -= cnt; + cursor -= cnt; + s->lim -= cnt; + adjust_eol_offsets(s, cnt); + } + + if((s->top - s->lim) < BOOST_WAVE_BSIZE) + { + uchar *buf = (uchar*) malloc(((s->lim - s->bot) + BOOST_WAVE_BSIZE)*sizeof(uchar)); + if (buf == 0) + { + using namespace std; // some systems have printf in std + if (0 != s->error_proc) { + (*s->error_proc)(s, lexing_exception::unexpected_error, + "Out of memory!"); + } + else + printf("Out of memory!\n"); + + /* get the scanner to stop */ + *cursor = 0; + return cursor; + } + + memmove(buf, s->tok, s->lim - s->tok); + s->tok = s->cur = buf; + s->ptr = &buf[s->ptr - s->bot]; + cursor = &buf[cursor - s->bot]; + s->lim = &buf[s->lim - s->bot]; + s->top = &s->lim[BOOST_WAVE_BSIZE]; + free(s->bot); + s->bot = buf; + } + + if (s->act != 0) { + cnt = s->last - s->act; + if (cnt > BOOST_WAVE_BSIZE) + cnt = BOOST_WAVE_BSIZE; + memmove(s->lim, s->act, cnt); + s->act += cnt; + if (cnt != BOOST_WAVE_BSIZE) + { + s->eof = &s->lim[cnt]; *(s->eof)++ = '\0'; + } + } + + /* backslash-newline erasing time */ + + /* first scan for backslash-newline and erase them */ + for (p = s->lim; p < s->lim + cnt - 2; ++p) + { + int len = 0; + if (is_backslash(p, s->lim + cnt, len)) + { + if (*(p+len) == '\n') + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + else if (*(p+len) == '\r') + { + if (*(p+len+1) == '\n') + { + int offset = len + 2; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + else + { + int offset = len + 1; + memmove(p, p + offset, s->lim + cnt - p - offset); + cnt -= offset; + --p; + } + aq_enqueue(s->eol_offsets, p - s->bot + 1); + } + } + } + + /* FIXME: the following code should be fixed to recognize correctly the + trigraph backslash token */ + + /* check to see if what we just read ends in a backslash */ + if (cnt >= 2) + { + uchar last = s->lim[cnt-1]; + uchar last2 = s->lim[cnt-2]; + /* check \ EOB */ + if (last == '\\') + { + int next = get_one_char(s); + /* check for \ \n or \ \r or \ \r \n straddling the border */ + if (next == '\n') + { + --cnt; /* chop the final \, we've already read the \n. */ + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + else if (next == '\r') + { + int next2 = get_one_char(s); + if (next2 == '\n') + { + --cnt; /* skip the backslash */ + } + else + { + /* rewind one, and skip one char */ + rewind_stream(s, -1); + --cnt; + } + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + else if (next != -1) /* -1 means end of file */ + { + /* next was something else, so rewind the stream */ + rewind_stream(s, -1); + } + } + /* check \ \r EOB */ + else if (last == '\r' && last2 == '\\') + { + int next = get_one_char(s); + if (next == '\n') + { + cnt -= 2; /* skip the \ \r */ + } + else + { + /* rewind one, and skip two chars */ + rewind_stream(s, -1); + cnt -= 2; + } + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + /* check \ \n EOB */ + else if (last == '\n' && last2 == '\\') + { + cnt -= 2; + aq_enqueue(s->eol_offsets, cnt + (s->lim - s->bot)); + } + } + + s->lim += cnt; + if (s->eof) /* eof needs adjusting if we erased backslash-newlines */ + { + s->eof = s->lim; + *(s->eof)++ = '\0'; + } + } + return cursor; +} + +/////////////////////////////////////////////////////////////////////////////// +// Special wrapper class holding the current cursor position +struct uchar_wrapper +{ + uchar_wrapper (uchar *base_cursor, unsigned int column = 1) + : base_cursor(base_cursor), column(column) + {} + + uchar_wrapper& operator++() + { + ++base_cursor; + ++column; + return *this; + } + + uchar_wrapper& operator--() + { + --base_cursor; + --column; + return *this; + } + + uchar operator* () const + { + return *base_cursor; + } + + operator uchar *() const + { + return base_cursor; + } + + friend std::ptrdiff_t + operator- (uchar_wrapper const& lhs, uchar_wrapper const& rhs) + { + return lhs.base_cursor - rhs.base_cursor; + } + + uchar *base_cursor; + unsigned int column; +}; + +/////////////////////////////////////////////////////////////////////////////// +boost::wave::token_id scan(Scanner *s) +{ + BOOST_ASSERT(0 != s->error_proc); // error handler must be given + + uchar_wrapper cursor (s->tok = s->cur, s->column = s->curr_column); + uchar_wrapper marker (s->ptr); + uchar_wrapper limit (s->lim); + +// include the correct Re2C token definition rules +#if BOOST_WAVE_USE_STRICT_LEXER != 0 +#include "strict_cpp_re.inc" +#else +#include "cpp_re.inc" +#endif + +} /* end of scan */ + +/////////////////////////////////////////////////////////////////////////////// +} // namespace re2clex +} // namespace cpplexer +} // namespace wave +} // namespace boost + +#undef BOOST_WAVE_RET +#undef BOOST_WAVE_BSIZE +#undef YYCTYPE +#undef YYCURSOR +#undef YYLIMIT +#undef YYMARKER +#undef YYFILL + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + diff --git a/extern/shiny/Preprocessor/cpp_re.inc b/extern/shiny/Preprocessor/cpp_re.inc new file mode 100644 index 000000000..afb7fc189 --- /dev/null +++ b/extern/shiny/Preprocessor/cpp_re.inc @@ -0,0 +1,9044 @@ +/* Generated by re2c 0.13.5 on Sun Jan 09 15:38:23 2011 */ +#line 1 "cpp.re" +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + + Copyright (c) 2001 Daniel C. Nuffer + Copyright (c) 2001-2011 Hartmut Kaiser. + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + This is a lexer conforming to the Standard with a few exceptions. + So it does allow the '$' to be part of identifiers. If you need strict + Standards conforming behaviour, please include the lexer definition + provided in the file strict_cpp.re. + + TODO: + handle errors better. +=============================================================================*/ + +#line 40 "cpp.re" + + + +#line 25 "cpp_re.inc" +{ + YYCTYPE yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + /* table 1 .. 8: 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 60, 32, 60, 60, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 60, 60, 52, 60, 60, 60, 60, 56, + 60, 60, 156, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 44, 57, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 58, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, + /* table 9 .. 12: 256 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 80, 0, 80, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 80, 64, 0, 64, 96, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 64, 64, 64, 64, 64, 0, + 64, 224, 224, 224, 224, 224, 224, 96, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 64, 0, 64, 64, 96, + 64, 224, 224, 224, 224, 224, 224, 96, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + }; + + if ((YYLIMIT - YYCURSOR) < 17) YYFILL(17); + yych = *YYCURSOR; + switch (yych) { + case 0x00: goto yy90; + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: goto yy93; + case '\t': + case '\v': + case '\f': goto yy84; + case '\n': goto yy87; + case '\r': goto yy89; + case ' ': goto yy86; + case '!': goto yy68; + case '"': goto yy79; + case '#': goto yy45; + case '$': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'S': + case 'T': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case 'h': + case 'j': + case 'k': + case 'q': + case 'y': + case 'z': goto yy82; + case '%': goto yy37; + case '&': goto yy62; + case '\'': goto yy77; + case '(': goto yy47; + case ')': goto yy49; + case '*': goto yy57; + case '+': goto yy53; + case ',': goto yy74; + case '-': goto yy55; + case '.': goto yy4; + case '/': goto yy2; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': goto yy6; + case ':': goto yy43; + case ';': goto yy51; + case '<': goto yy33; + case '=': goto yy70; + case '>': goto yy72; + case '?': goto yy31; + case 'L': goto yy76; + case 'R': goto yy80; + case 'U': goto yy81; + case '[': goto yy39; + case '\\': goto yy83; + case ']': goto yy41; + case '^': goto yy59; + case '_': goto yy28; + case 'a': goto yy8; + case 'b': goto yy10; + case 'c': goto yy11; + case 'd': goto yy12; + case 'e': goto yy13; + case 'f': goto yy14; + case 'g': goto yy15; + case 'i': goto yy16; + case 'l': goto yy17; + case 'm': goto yy18; + case 'n': goto yy19; + case 'o': goto yy20; + case 'p': goto yy21; + case 'r': goto yy22; + case 's': goto yy23; + case 't': goto yy24; + case 'u': goto yy25; + case 'v': goto yy26; + case 'w': goto yy27; + case 'x': goto yy61; + case '{': goto yy29; + case '|': goto yy64; + case '}': goto yy35; + case '~': goto yy66; + default: goto yy92; + } +yy2: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '.') { + if (yych == '*') goto yy998; + } else { + if (yych <= '/') goto yy996; + if (yych == '=') goto yy994; + } +#line 188 "cpp.re" + { BOOST_WAVE_RET(T_DIVIDE); } +#line 238 "cpp_re.inc" +yy4: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '-') { + if (yych == '*') goto yy988; + } else { + if (yych <= '.') goto yy990; + if (yych <= '/') goto yy5; + if (yych <= '9') goto yy991; + } +yy5: +#line 174 "cpp.re" + { BOOST_WAVE_RET(T_DOT); } +#line 252 "cpp_re.inc" +yy6: + ++YYCURSOR; +yy7: +#line 45 "cpp.re" + { goto pp_number; } +#line 258 "cpp_re.inc" +yy8: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'l': goto yy964; + case 'n': goto yy965; + case 's': goto yy966; + case 'u': goto yy967; + default: goto yy109; + } +yy9: +#line 290 "cpp.re" + { BOOST_WAVE_RET(T_IDENTIFIER); } +#line 272 "cpp_re.inc" +yy10: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'n') { + if (yych == 'i') goto yy946; + goto yy109; + } else { + if (yych <= 'o') goto yy947; + if (yych == 'r') goto yy948; + goto yy109; + } +yy11: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'a': goto yy893; + case 'h': goto yy894; + case 'l': goto yy895; + case 'o': goto yy896; + default: goto yy109; + } +yy12: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'n') { + if (yych == 'e') goto yy855; + goto yy109; + } else { + if (yych <= 'o') goto yy856; + if (yych == 'y') goto yy858; + goto yy109; + } +yy13: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'm') { + if (yych == 'l') goto yy830; + goto yy109; + } else { + if (yych <= 'n') goto yy831; + if (yych == 'x') goto yy832; + goto yy109; + } +yy14: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'a': goto yy811; + case 'l': goto yy812; + case 'o': goto yy813; + case 'r': goto yy814; + default: goto yy109; + } +yy15: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy807; + goto yy109; +yy16: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'l') { + if (yych == 'f') goto yy791; + goto yy109; + } else { + if (yych <= 'm') goto yy793; + if (yych <= 'n') goto yy794; + goto yy109; + } +yy17: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy787; + goto yy109; +yy18: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy780; + goto yy109; +yy19: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'e') { + if (yych == 'a') goto yy747; + if (yych <= 'd') goto yy109; + goto yy748; + } else { + if (yych <= 'o') { + if (yych <= 'n') goto yy109; + goto yy749; + } else { + if (yych == 'u') goto yy750; + goto yy109; + } + } +yy20: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'p') goto yy733; + if (yych == 'r') goto yy734; + goto yy109; +yy21: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy712; + if (yych == 'u') goto yy713; + goto yy109; +yy22: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy684; + goto yy109; +yy23: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 's') { + if (yych <= 'g') goto yy109; + if (yych <= 'h') goto yy638; + if (yych <= 'i') goto yy639; + goto yy109; + } else { + if (yych <= 't') goto yy640; + if (yych == 'w') goto yy641; + goto yy109; + } +yy24: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'h') { + if (yych == 'e') goto yy591; + if (yych <= 'g') goto yy109; + goto yy592; + } else { + if (yych <= 'r') { + if (yych <= 'q') goto yy109; + goto yy593; + } else { + if (yych == 'y') goto yy594; + goto yy109; + } + } +yy25: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '8') { + if (yych <= '&') { + if (yych == '"') goto yy129; + goto yy109; + } else { + if (yych <= '\'') goto yy131; + if (yych <= '7') goto yy109; + goto yy573; + } + } else { + if (yych <= 'm') { + if (yych == 'R') goto yy128; + goto yy109; + } else { + if (yych <= 'n') goto yy574; + if (yych == 's') goto yy575; + goto yy109; + } + } +yy26: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy555; + if (yych == 'o') goto yy556; + goto yy109; +yy27: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'c') goto yy543; + if (yych == 'h') goto yy544; + goto yy109; +yy28: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case '_': goto yy454; + case 'a': goto yy455; + case 'b': goto yy456; + case 'c': goto yy457; + case 'd': goto yy458; + case 'f': goto yy459; + case 'i': goto yy460; + case 's': goto yy461; + default: goto yy109; + } +yy29: + ++YYCURSOR; +#line 138 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACE); } +#line 466 "cpp_re.inc" +yy31: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '?') goto yy419; +yy32: +#line 163 "cpp.re" + { BOOST_WAVE_RET(T_QUESTION_MARK); } +#line 474 "cpp_re.inc" +yy33: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= ':') { + if (yych == '%') goto yy415; + if (yych >= ':') goto yy413; + } else { + if (yych <= ';') goto yy34; + if (yych <= '<') goto yy411; + if (yych <= '=') goto yy409; + } +yy34: +#line 204 "cpp.re" + { BOOST_WAVE_RET(T_LESS); } +#line 488 "cpp_re.inc" +yy35: + ++YYCURSOR; +#line 141 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACE); } +#line 493 "cpp_re.inc" +yy37: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '<') { + if (yych == ':') goto yy400; + } else { + if (yych <= '=') goto yy402; + if (yych <= '>') goto yy404; + } +#line 189 "cpp.re" + { BOOST_WAVE_RET(T_PERCENT); } +#line 504 "cpp_re.inc" +yy39: + ++YYCURSOR; +#line 144 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACKET); } +#line 509 "cpp_re.inc" +yy41: + ++YYCURSOR; +#line 147 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACKET); } +#line 514 "cpp_re.inc" +yy43: + ++YYCURSOR; + if ((yych = *YYCURSOR) == ':') goto yy396; + if (yych == '>') goto yy398; +#line 161 "cpp.re" + { BOOST_WAVE_RET(T_COLON); } +#line 521 "cpp_re.inc" +yy45: + yyaccept = 3; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'c') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy273; + } else { + if (yych <= '\f') goto yy273; + if (yych >= ' ') goto yy273; + } + } else { + if (yych <= '.') { + if (yych == '#') goto yy284; + } else { + if (yych <= '/') goto yy273; + if (yych == '?') goto yy283; + } + } + } else { + if (yych <= 'p') { + if (yych <= 'i') { + if (yych <= 'e') goto yy273; + if (yych >= 'i') goto yy273; + } else { + if (yych == 'l') goto yy273; + if (yych >= 'p') goto yy273; + } + } else { + if (yych <= 't') { + if (yych == 'r') goto yy273; + } else { + if (yych == 'v') goto yy46; + if (yych <= 'w') goto yy273; + } + } + } +yy46: +#line 150 "cpp.re" + { BOOST_WAVE_RET(T_POUND); } +#line 562 "cpp_re.inc" +yy47: + ++YYCURSOR; +#line 158 "cpp.re" + { BOOST_WAVE_RET(T_LEFTPAREN); } +#line 567 "cpp_re.inc" +yy49: + ++YYCURSOR; +#line 159 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTPAREN); } +#line 572 "cpp_re.inc" +yy51: + ++YYCURSOR; +#line 160 "cpp.re" + { BOOST_WAVE_RET(T_SEMICOLON); } +#line 577 "cpp_re.inc" +yy53: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '+') goto yy268; + if (yych == '=') goto yy270; +#line 185 "cpp.re" + { BOOST_WAVE_RET(T_PLUS); } +#line 584 "cpp_re.inc" +yy55: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '<') { + if (yych == '-') goto yy262; + } else { + if (yych <= '=') goto yy264; + if (yych <= '>') goto yy260; + } +#line 186 "cpp.re" + { BOOST_WAVE_RET(T_MINUS); } +#line 595 "cpp_re.inc" +yy57: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy258; +#line 187 "cpp.re" + { BOOST_WAVE_RET(T_STAR); } +#line 601 "cpp_re.inc" +yy59: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy256; +#line 190 "cpp.re" + { BOOST_WAVE_RET(T_XOR); } +#line 607 "cpp_re.inc" +yy61: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy249; + goto yy109; +yy62: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '&') goto yy245; + if (yych == '=') goto yy247; +#line 193 "cpp.re" + { BOOST_WAVE_RET(T_AND); } +#line 619 "cpp_re.inc" +yy64: + yyaccept = 4; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '>') { + if (yych == '=') goto yy240; + } else { + if (yych <= '?') goto yy237; + if (yych == '|') goto yy238; + } +yy65: +#line 195 "cpp.re" + { BOOST_WAVE_RET(T_OR); } +#line 632 "cpp_re.inc" +yy66: + ++YYCURSOR; +#line 198 "cpp.re" + { BOOST_WAVE_RET(T_COMPL); } +#line 637 "cpp_re.inc" +yy68: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy235; +#line 201 "cpp.re" + { BOOST_WAVE_RET(T_NOT); } +#line 643 "cpp_re.inc" +yy70: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy233; +#line 203 "cpp.re" + { BOOST_WAVE_RET(T_ASSIGN); } +#line 649 "cpp_re.inc" +yy72: + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '<') goto yy73; + if (yych <= '=') goto yy227; + if (yych <= '>') goto yy229; +yy73: +#line 205 "cpp.re" + { BOOST_WAVE_RET(T_GREATER); } +#line 658 "cpp_re.inc" +yy74: + ++YYCURSOR; +#line 237 "cpp.re" + { BOOST_WAVE_RET(T_COMMA); } +#line 663 "cpp_re.inc" +yy76: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '?') { + if (yych <= '&') { + if (yych <= '"') { + if (yych <= '!') goto yy9; + goto yy137; + } else { + if (yych == '$') goto yy108; + goto yy9; + } + } else { + if (yych <= '/') { + if (yych <= '\'') goto yy226; + goto yy9; + } else { + if (yych <= '9') goto yy108; + if (yych <= '>') goto yy9; + goto yy111; + } + } + } else { + if (yych <= '[') { + if (yych <= 'Q') { + if (yych <= '@') goto yy9; + goto yy108; + } else { + if (yych <= 'R') goto yy225; + if (yych <= 'Z') goto yy108; + goto yy9; + } + } else { + if (yych <= '_') { + if (yych <= '\\') goto yy110; + if (yych <= '^') goto yy9; + goto yy108; + } else { + if (yych <= '`') goto yy9; + if (yych <= 'z') goto yy108; + goto yy9; + } + } + } +yy77: + yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\f') { + if (yych == '\t') goto yy182; + if (yych >= '\v') goto yy182; + } else { + if (yych <= 0x1F) goto yy78; + if (yych != '\'') goto yy182; + } +yy78: +#line 339 "cpp.re" + { BOOST_WAVE_RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); } +#line 721 "cpp_re.inc" +yy79: + yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\n') { + if (yych == '\t') goto yy138; + goto yy78; + } else { + if (yych <= '\f') goto yy138; + if (yych <= 0x1F) goto yy78; + goto yy138; + } +yy80: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '"') goto yy135; + goto yy109; +yy81: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '&') { + if (yych == '"') goto yy129; + goto yy109; + } else { + if (yych <= '\'') goto yy131; + if (yych == 'R') goto yy128; + goto yy109; + } +yy82: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + goto yy109; +yy83: + yyaccept = 5; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'U') goto yy100; + if (yych == 'u') goto yy98; + goto yy78; +yy84: + ++YYCURSOR; + yych = *YYCURSOR; + goto yy97; +yy85: +#line 319 "cpp.re" + { BOOST_WAVE_RET(T_SPACE); } +#line 766 "cpp_re.inc" +yy86: + yych = *++YYCURSOR; + goto yy97; +yy87: + ++YYCURSOR; +yy88: +#line 322 "cpp.re" + { + s->line++; + cursor.column = 1; + BOOST_WAVE_RET(T_NEWLINE); + } +#line 779 "cpp_re.inc" +yy89: + yych = *++YYCURSOR; + if (yych == '\n') goto yy95; + goto yy88; +yy90: + ++YYCURSOR; +#line 329 "cpp.re" + { + if (s->eof && cursor != s->eof) + { + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\000' in input stream"); + } + BOOST_WAVE_RET(T_EOF); + } +#line 796 "cpp_re.inc" +yy92: + yych = *++YYCURSOR; + goto yy78; +yy93: + ++YYCURSOR; +#line 342 "cpp.re" + { + // flag the error + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\%03o' in input stream", *--YYCURSOR); + } +#line 809 "cpp_re.inc" +yy95: + yych = *++YYCURSOR; + goto yy88; +yy96: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy97: + if (yybm[256+yych] & 16) { + goto yy96; + } + goto yy85; +yy98: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy125; + } else { + if (yych <= 'F') goto yy125; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy125; + } +yy99: + YYCURSOR = YYMARKER; + if (yyaccept <= 56) { + if (yyaccept <= 28) { + if (yyaccept <= 14) { + if (yyaccept <= 7) { + if (yyaccept <= 3) { + if (yyaccept <= 1) { + if (yyaccept <= 0) { + goto yy5; + } else { + goto yy9; + } + } else { + if (yyaccept <= 2) { + goto yy32; + } else { + goto yy46; + } + } + } else { + if (yyaccept <= 5) { + if (yyaccept <= 4) { + goto yy65; + } else { + goto yy78; + } + } else { + if (yyaccept <= 6) { + goto yy142; + } else { + goto yy192; + } + } + } + } else { + if (yyaccept <= 11) { + if (yyaccept <= 9) { + if (yyaccept <= 8) { + goto yy251; + } else { + goto yy255; + } + } else { + if (yyaccept <= 10) { + goto yy291; + } else { + goto yy306; + } + } + } else { + if (yyaccept <= 13) { + if (yyaccept <= 12) { + goto yy401; + } else { + goto yy429; + } + } else { + goto yy433; + } + } + } + } else { + if (yyaccept <= 21) { + if (yyaccept <= 18) { + if (yyaccept <= 16) { + if (yyaccept <= 15) { + goto yy437; + } else { + goto yy468; + } + } else { + if (yyaccept <= 17) { + goto yy474; + } else { + goto yy482; + } + } + } else { + if (yyaccept <= 20) { + if (yyaccept <= 19) { + goto yy490; + } else { + goto yy495; + } + } else { + goto yy500; + } + } + } else { + if (yyaccept <= 25) { + if (yyaccept <= 23) { + if (yyaccept <= 22) { + goto yy503; + } else { + goto yy513; + } + } else { + if (yyaccept <= 24) { + goto yy519; + } else { + goto yy522; + } + } + } else { + if (yyaccept <= 27) { + if (yyaccept <= 26) { + goto yy529; + } else { + goto yy536; + } + } else { + goto yy538; + } + } + } + } + } else { + if (yyaccept <= 42) { + if (yyaccept <= 35) { + if (yyaccept <= 32) { + if (yyaccept <= 30) { + if (yyaccept <= 29) { + goto yy540; + } else { + goto yy542; + } + } else { + if (yyaccept <= 31) { + goto yy548; + } else { + goto yy554; + } + } + } else { + if (yyaccept <= 34) { + if (yyaccept <= 33) { + goto yy564; + } else { + goto yy566; + } + } else { + goto yy572; + } + } + } else { + if (yyaccept <= 39) { + if (yyaccept <= 37) { + if (yyaccept <= 36) { + goto yy579; + } else { + goto yy587; + } + } else { + if (yyaccept <= 38) { + goto yy590; + } else { + goto yy603; + } + } + } else { + if (yyaccept <= 41) { + if (yyaccept <= 40) { + goto yy605; + } else { + goto yy608; + } + } else { + goto yy611; + } + } + } + } else { + if (yyaccept <= 49) { + if (yyaccept <= 46) { + if (yyaccept <= 44) { + if (yyaccept <= 43) { + goto yy613; + } else { + goto yy619; + } + } else { + if (yyaccept <= 45) { + goto yy628; + } else { + goto yy630; + } + } + } else { + if (yyaccept <= 48) { + if (yyaccept <= 47) { + goto yy637; + } else { + goto yy646; + } + } else { + goto yy652; + } + } + } else { + if (yyaccept <= 53) { + if (yyaccept <= 51) { + if (yyaccept <= 50) { + goto yy656; + } else { + goto yy663; + } + } else { + if (yyaccept <= 52) { + goto yy669; + } else { + goto yy675; + } + } + } else { + if (yyaccept <= 55) { + if (yyaccept <= 54) { + goto yy679; + } else { + goto yy683; + } + } else { + goto yy691; + } + } + } + } + } + } else { + if (yyaccept <= 85) { + if (yyaccept <= 71) { + if (yyaccept <= 64) { + if (yyaccept <= 60) { + if (yyaccept <= 58) { + if (yyaccept <= 57) { + goto yy705; + } else { + goto yy711; + } + } else { + if (yyaccept <= 59) { + goto yy718; + } else { + goto yy727; + } + } + } else { + if (yyaccept <= 62) { + if (yyaccept <= 61) { + goto yy732; + } else { + goto yy735; + } + } else { + if (yyaccept <= 63) { + goto yy739; + } else { + goto yy746; + } + } + } + } else { + if (yyaccept <= 68) { + if (yyaccept <= 66) { + if (yyaccept <= 65) { + goto yy756; + } else { + goto yy759; + } + } else { + if (yyaccept <= 67) { + goto yy763; + } else { + goto yy769; + } + } + } else { + if (yyaccept <= 70) { + if (yyaccept <= 69) { + goto yy771; + } else { + goto yy779; + } + } else { + goto yy786; + } + } + } + } else { + if (yyaccept <= 78) { + if (yyaccept <= 75) { + if (yyaccept <= 73) { + if (yyaccept <= 72) { + goto yy790; + } else { + goto yy792; + } + } else { + if (yyaccept <= 74) { + goto yy797; + } else { + goto yy801; + } + } + } else { + if (yyaccept <= 77) { + if (yyaccept <= 76) { + goto yy806; + } else { + goto yy810; + } + } else { + goto yy819; + } + } + } else { + if (yyaccept <= 82) { + if (yyaccept <= 80) { + if (yyaccept <= 79) { + goto yy821; + } else { + goto yy825; + } + } else { + if (yyaccept <= 81) { + goto yy829; + } else { + goto yy838; + } + } + } else { + if (yyaccept <= 84) { + if (yyaccept <= 83) { + goto yy843; + } else { + goto yy848; + } + } else { + goto yy851; + } + } + } + } + } else { + if (yyaccept <= 99) { + if (yyaccept <= 92) { + if (yyaccept <= 89) { + if (yyaccept <= 87) { + if (yyaccept <= 86) { + goto yy854; + } else { + goto yy857; + } + } else { + if (yyaccept <= 88) { + goto yy869; + } else { + goto yy874; + } + } + } else { + if (yyaccept <= 91) { + if (yyaccept <= 90) { + goto yy881; + } else { + goto yy886; + } + } else { + goto yy892; + } + } + } else { + if (yyaccept <= 96) { + if (yyaccept <= 94) { + if (yyaccept <= 93) { + goto yy901; + } else { + goto yy908; + } + } else { + if (yyaccept <= 95) { + goto yy910; + } else { + goto yy916; + } + } + } else { + if (yyaccept <= 98) { + if (yyaccept <= 97) { + goto yy921; + } else { + goto yy925; + } + } else { + goto yy928; + } + } + } + } else { + if (yyaccept <= 106) { + if (yyaccept <= 103) { + if (yyaccept <= 101) { + if (yyaccept <= 100) { + goto yy934; + } else { + goto yy938; + } + } else { + if (yyaccept <= 102) { + goto yy943; + } else { + goto yy945; + } + } + } else { + if (yyaccept <= 105) { + if (yyaccept <= 104) { + goto yy952; + } else { + goto yy955; + } + } else { + goto yy960; + } + } + } else { + if (yyaccept <= 110) { + if (yyaccept <= 108) { + if (yyaccept <= 107) { + goto yy963; + } else { + goto yy970; + } + } else { + if (yyaccept <= 109) { + goto yy972; + } else { + goto yy974; + } + } + } else { + if (yyaccept <= 112) { + if (yyaccept <= 111) { + goto yy978; + } else { + goto yy985; + } + } else { + goto yy987; + } + } + } + } + } + } +yy100: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy101; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy101: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy102; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy102: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy103; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy103: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy104; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy104: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy105; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy105: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy106; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy106: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy107; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy107: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy108; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy108: + yyaccept = 1; + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy109: + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych != '\\') goto yy9; +yy110: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == 'U') goto yy114; + if (yych == 'u') goto yy113; + goto yy99; +yy111: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych != '?') goto yy99; + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == '/') goto yy110; + goto yy99; +yy113: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy122; + goto yy99; + } else { + if (yych <= 'F') goto yy122; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy122; + goto yy99; + } +yy114: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy115; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy115: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy116; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy116: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy117; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy117: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy118; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy118: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy119; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy119: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy120; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy120: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy121; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy121: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy108; + goto yy99; + } else { + if (yych <= 'F') goto yy108; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy108; + goto yy99; + } +yy122: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy123; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy123: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy124; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy124: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy108; + goto yy99; + } else { + if (yych <= 'F') goto yy108; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy108; + goto yy99; + } +yy125: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy126; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy126: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy127; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy127: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy108; + goto yy99; + } else { + if (yych <= 'F') goto yy108; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy108; + goto yy99; + } +yy128: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '"') goto yy133; + goto yy109; +yy129: + ++YYCURSOR; +#line 274 "cpp.re" + { + if (s->act_in_cpp0x_mode) + goto extstringlit; + --YYCURSOR; + BOOST_WAVE_RET(T_IDENTIFIER); + } +#line 1591 "cpp_re.inc" +yy131: + ++YYCURSOR; +#line 266 "cpp.re" + { + if (s->act_in_cpp0x_mode) + goto extcharlit; + --YYCURSOR; + BOOST_WAVE_RET(T_IDENTIFIER); + } +#line 1601 "cpp_re.inc" +yy133: + ++YYCURSOR; +#line 282 "cpp.re" + { + if (s->act_in_cpp0x_mode) + goto extrawstringlit; + --YYCURSOR; + BOOST_WAVE_RET(T_IDENTIFIER); + } +#line 1611 "cpp_re.inc" +yy135: + ++YYCURSOR; +#line 258 "cpp.re" + { + if (s->act_in_cpp0x_mode) + goto extrawstringlit; + --YYCURSOR; + BOOST_WAVE_RET(T_IDENTIFIER); + } +#line 1621 "cpp_re.inc" +yy137: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy138: + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych >= '\\') goto yy140; +yy139: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy152; +yy140: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy137; + goto yy99; + } else { + if (yych <= '\'') goto yy137; + if (yych <= '/') goto yy99; + goto yy147; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy145; + goto yy99; + } else { + if (yych <= 'U') goto yy144; + if (yych == '\\') goto yy137; + goto yy99; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy137; + if (yych <= 'e') goto yy99; + goto yy137; + } else { + if (yych == 'n') goto yy137; + if (yych <= 'q') goto yy99; + goto yy137; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy99; + if (yych <= 't') goto yy137; + goto yy143; + } else { + if (yych <= 'v') goto yy137; + if (yych == 'x') goto yy146; + goto yy99; + } + } + } +yy141: + ++YYCURSOR; +yy142: +#line 255 "cpp.re" + { BOOST_WAVE_RET(T_STRINGLIT); } +#line 1695 "cpp_re.inc" +yy143: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy178; + goto yy99; + } else { + if (yych <= 'F') goto yy178; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy178; + goto yy99; + } +yy144: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy171; + goto yy99; + } else { + if (yych <= 'F') goto yy171; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy171; + goto yy99; + } +yy145: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy151; + goto yy140; +yy146: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 128) { + goto yy149; + } + goto yy99; +yy147: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '"') { + if (yych <= '\n') { + if (yych == '\t') goto yy137; + goto yy99; + } else { + if (yych <= '\f') goto yy137; + if (yych <= 0x1F) goto yy99; + if (yych <= '!') goto yy137; + goto yy141; + } + } else { + if (yych <= '>') { + if (yych <= '/') goto yy137; + if (yych >= '8') goto yy137; + } else { + if (yych <= '?') goto yy139; + if (yych == '\\') goto yy140; + goto yy137; + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy139; + goto yy140; +yy149: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 128) { + goto yy149; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy137; + goto yy99; + } else { + if (yych <= '\f') goto yy137; + if (yych <= 0x1F) goto yy99; + goto yy137; + } + } else { + if (yych <= '?') { + if (yych <= '"') goto yy141; + if (yych <= '>') goto yy137; + goto yy139; + } else { + if (yych == '\\') goto yy140; + goto yy137; + } + } +yy151: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych >= '\\') goto yy140; +yy152: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 1) { + goto yy152; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy137; + goto yy99; + } else { + if (yych <= '\f') goto yy137; + if (yych <= 0x1F) goto yy99; + goto yy137; + } + } else { + if (yych <= '/') { + if (yych <= '"') goto yy141; + if (yych <= '.') goto yy137; + } else { + if (yych == '\\') goto yy140; + goto yy137; + } + } +yy154: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 2) { + goto yy154; + } + if (yych <= '7') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy158; + if (yych <= '/') goto yy137; + goto yy147; + } + } + } else { + if (yych <= 'U') { + if (yych == '?') goto yy159; + if (yych <= 'T') goto yy137; + goto yy157; + } else { + if (yych <= 'u') { + if (yych <= 't') goto yy137; + } else { + if (yych == 'x') goto yy149; + goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + goto yy168; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + goto yy168; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych <= 'f') goto yy168; + goto yy137; + } + } + } +yy157: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + goto yy161; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + goto yy161; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych <= 'f') goto yy161; + goto yy137; + } + } + } +yy158: + yyaccept = 6; + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy142; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy139; + goto yy140; +yy159: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych >= '\\') goto yy140; + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 1) { + goto yy152; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy137; + goto yy99; + } else { + if (yych <= '\f') goto yy137; + if (yych <= 0x1F) goto yy99; + goto yy137; + } + } else { + if (yych <= '/') { + if (yych <= '"') goto yy141; + if (yych <= '.') goto yy137; + goto yy154; + } else { + if (yych == '\\') goto yy140; + goto yy137; + } + } +yy161: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy139; + goto yy140; +yy168: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy137; + if (yych <= '\n') goto yy99; + goto yy137; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy99; + goto yy137; + } else { + if (yych <= '"') goto yy141; + if (yych <= '/') goto yy137; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy139; + if (yych <= '@') goto yy137; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy137; + goto yy140; + } else { + if (yych <= '`') goto yy137; + if (yych >= 'g') goto yy137; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[256+yych] & 64) { + goto yy137; + } + if (yych <= '!') goto yy99; + if (yych <= '"') goto yy141; + if (yych <= '[') goto yy139; + goto yy140; +yy171: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy172; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy172: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy173; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy173: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy174; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy174: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy175; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy175: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy176; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy176: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy177; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy177: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy137; + goto yy99; + } else { + if (yych <= 'F') goto yy137; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy137; + goto yy99; + } +yy178: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy179; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy179: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy180; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy180: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy137; + goto yy99; + } else { + if (yych <= 'F') goto yy137; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy137; + goto yy99; + } +yy181: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy182: + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych >= '\\') goto yy184; +yy183: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy196; +yy184: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy181; + goto yy99; + } else { + if (yych <= '\'') goto yy181; + if (yych <= '/') goto yy99; + goto yy189; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy187; + goto yy99; + } else { + if (yych <= 'U') goto yy186; + if (yych == '\\') goto yy181; + goto yy99; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy181; + if (yych <= 'e') goto yy99; + goto yy181; + } else { + if (yych == 'n') goto yy181; + if (yych <= 'q') goto yy99; + goto yy181; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy99; + if (yych <= 't') goto yy181; + } else { + if (yych <= 'v') goto yy181; + if (yych == 'x') goto yy188; + goto yy99; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy222; + goto yy99; + } else { + if (yych <= 'F') goto yy222; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy222; + goto yy99; + } +yy186: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy215; + goto yy99; + } else { + if (yych <= 'F') goto yy215; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy215; + goto yy99; + } +yy187: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy195; + goto yy184; +yy188: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy193; + goto yy99; + } else { + if (yych <= 'F') goto yy193; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy193; + goto yy99; + } +yy189: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\'') { + if (yych <= '\n') { + if (yych == '\t') goto yy181; + goto yy99; + } else { + if (yych <= '\f') goto yy181; + if (yych <= 0x1F) goto yy99; + if (yych <= '&') goto yy181; + goto yy191; + } + } else { + if (yych <= '>') { + if (yych <= '/') goto yy181; + if (yych >= '8') goto yy181; + } else { + if (yych <= '?') goto yy183; + if (yych == '\\') goto yy184; + goto yy181; + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy183; + goto yy184; +yy191: + ++YYCURSOR; +yy192: +#line 252 "cpp.re" + { BOOST_WAVE_RET(T_CHARLIT); } +#line 2542 "cpp_re.inc" +yy193: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + goto yy193; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + goto yy193; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych <= 'f') goto yy193; + goto yy181; + } + } + } +yy195: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych >= '\\') goto yy184; +yy196: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\'') { + if (yych <= '\n') { + if (yych == '\t') goto yy181; + goto yy99; + } else { + if (yych <= '\f') goto yy181; + if (yych <= 0x1F) goto yy99; + if (yych <= '&') goto yy181; + goto yy191; + } + } else { + if (yych <= '>') { + if (yych != '/') goto yy181; + } else { + if (yych <= '?') goto yy196; + if (yych == '\\') goto yy184; + goto yy181; + } + } +yy198: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '>') { + if (yych <= 0x1F) { + if (yych <= '\t') { + if (yych <= 0x08) goto yy99; + goto yy181; + } else { + if (yych <= '\n') goto yy99; + if (yych <= '\f') goto yy181; + goto yy99; + } + } else { + if (yych <= '\'') { + if (yych <= '&') goto yy181; + goto yy202; + } else { + if (yych <= '/') goto yy181; + if (yych <= '7') goto yy189; + goto yy181; + } + } + } else { + if (yych <= '\\') { + if (yych <= 'T') { + if (yych <= '?') goto yy203; + goto yy181; + } else { + if (yych <= 'U') goto yy201; + if (yych <= '[') goto yy181; + goto yy198; + } + } else { + if (yych <= 'u') { + if (yych <= 't') goto yy181; + } else { + if (yych == 'x') goto yy193; + goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + goto yy212; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + goto yy212; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych <= 'f') goto yy212; + goto yy181; + } + } + } +yy201: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + goto yy205; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + goto yy205; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych <= 'f') goto yy205; + goto yy181; + } + } + } +yy202: + yyaccept = 7; + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy192; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy183; + goto yy184; +yy203: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych >= '\\') goto yy184; + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\'') { + if (yych <= '\n') { + if (yych == '\t') goto yy181; + goto yy99; + } else { + if (yych <= '\f') goto yy181; + if (yych <= 0x1F) goto yy99; + if (yych <= '&') goto yy181; + goto yy191; + } + } else { + if (yych <= '>') { + if (yych == '/') goto yy198; + goto yy181; + } else { + if (yych <= '?') goto yy196; + if (yych == '\\') goto yy184; + goto yy181; + } + } +yy205: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy183; + goto yy184; +yy212: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy181; + if (yych <= '\n') goto yy99; + goto yy181; + } else { + if (yych <= '&') { + if (yych <= 0x1F) goto yy99; + goto yy181; + } else { + if (yych <= '\'') goto yy191; + if (yych <= '/') goto yy181; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy183; + if (yych <= '@') goto yy181; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy181; + goto yy184; + } else { + if (yych <= '`') goto yy181; + if (yych >= 'g') goto yy181; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 4) { + goto yy181; + } + if (yych <= '&') goto yy99; + if (yych <= '\'') goto yy191; + if (yych <= '[') goto yy183; + goto yy184; +yy215: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy216; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy216: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy217; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy217: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy218; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy218: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy219; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy219: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy220; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy220: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy221; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy221: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy181; + goto yy99; + } else { + if (yych <= 'F') goto yy181; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy181; + goto yy99; + } +yy222: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy223; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy223: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych >= ':') goto yy99; + } else { + if (yych <= 'F') goto yy224; + if (yych <= '`') goto yy99; + if (yych >= 'g') goto yy99; + } +yy224: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy99; + if (yych <= '9') goto yy181; + goto yy99; + } else { + if (yych <= 'F') goto yy181; + if (yych <= '`') goto yy99; + if (yych <= 'f') goto yy181; + goto yy99; + } +yy225: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '"') goto yy135; + goto yy109; +yy226: + yych = *++YYCURSOR; + if (yych == '\'') goto yy99; + goto yy182; +yy227: + ++YYCURSOR; +#line 227 "cpp.re" + { BOOST_WAVE_RET(T_GREATEREQUAL); } +#line 3175 "cpp_re.inc" +yy229: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy231; +#line 220 "cpp.re" + { BOOST_WAVE_RET(T_SHIFTRIGHT); } +#line 3181 "cpp_re.inc" +yy231: + ++YYCURSOR; +#line 221 "cpp.re" + { BOOST_WAVE_RET(T_SHIFTRIGHTASSIGN); } +#line 3186 "cpp_re.inc" +yy233: + ++YYCURSOR; +#line 223 "cpp.re" + { BOOST_WAVE_RET(T_EQUAL); } +#line 3191 "cpp_re.inc" +yy235: + ++YYCURSOR; +#line 224 "cpp.re" + { BOOST_WAVE_RET(T_NOTEQUAL); } +#line 3196 "cpp_re.inc" +yy237: + yych = *++YYCURSOR; + if (yych == '?') goto yy242; + goto yy99; +yy238: + ++YYCURSOR; +#line 230 "cpp.re" + { BOOST_WAVE_RET(T_OROR); } +#line 3205 "cpp_re.inc" +yy240: + ++YYCURSOR; +#line 216 "cpp.re" + { BOOST_WAVE_RET(T_ORASSIGN); } +#line 3210 "cpp_re.inc" +yy242: + yych = *++YYCURSOR; + if (yych != '!') goto yy99; + ++YYCURSOR; +#line 232 "cpp.re" + { BOOST_WAVE_RET(T_OROR_TRIGRAPH); } +#line 3217 "cpp_re.inc" +yy245: + ++YYCURSOR; +#line 228 "cpp.re" + { BOOST_WAVE_RET(T_ANDAND); } +#line 3222 "cpp_re.inc" +yy247: + ++YYCURSOR; +#line 214 "cpp.re" + { BOOST_WAVE_RET(T_ANDASSIGN); } +#line 3227 "cpp_re.inc" +yy249: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 8; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy252; + if (yych <= '`') goto yy251; + if (yych <= 'z') goto yy108; + } + } +yy251: +#line 192 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_XOR_ALT); } +#line 3254 "cpp_re.inc" +yy252: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'q') goto yy109; + yyaccept = 9; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy255: +#line 212 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_XORASSIGN_ALT); } +#line 3272 "cpp_re.inc" +yy256: + ++YYCURSOR; +#line 211 "cpp.re" + { BOOST_WAVE_RET(T_XORASSIGN); } +#line 3277 "cpp_re.inc" +yy258: + ++YYCURSOR; +#line 208 "cpp.re" + { BOOST_WAVE_RET(T_STARASSIGN); } +#line 3282 "cpp_re.inc" +yy260: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '*') goto yy266; +#line 248 "cpp.re" + { BOOST_WAVE_RET(T_ARROW); } +#line 3288 "cpp_re.inc" +yy262: + ++YYCURSOR; +#line 236 "cpp.re" + { BOOST_WAVE_RET(T_MINUSMINUS); } +#line 3293 "cpp_re.inc" +yy264: + ++YYCURSOR; +#line 207 "cpp.re" + { BOOST_WAVE_RET(T_MINUSASSIGN); } +#line 3298 "cpp_re.inc" +yy266: + ++YYCURSOR; +#line 239 "cpp.re" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + BOOST_WAVE_RET(T_ARROW); + } + else { + BOOST_WAVE_RET(T_ARROWSTAR); + } + } +#line 3311 "cpp_re.inc" +yy268: + ++YYCURSOR; +#line 235 "cpp.re" + { BOOST_WAVE_RET(T_PLUSPLUS); } +#line 3316 "cpp_re.inc" +yy270: + ++YYCURSOR; +#line 206 "cpp.re" + { BOOST_WAVE_RET(T_PLUSASSIGN); } +#line 3321 "cpp_re.inc" +yy272: + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 12) YYFILL(12); + yych = *YYCURSOR; +yy273: + if (yych <= 'h') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy272; + goto yy99; + } else { + if (yych <= '\f') goto yy272; + if (yych <= 0x1F) goto yy99; + goto yy272; + } + } else { + if (yych <= 'c') { + if (yych != '/') goto yy99; + } else { + if (yych <= 'd') goto yy281; + if (yych <= 'e') goto yy275; + goto yy99; + } + } + } else { + if (yych <= 'q') { + if (yych <= 'l') { + if (yych <= 'i') goto yy282; + if (yych <= 'k') goto yy99; + goto yy279; + } else { + if (yych == 'p') goto yy278; + goto yy99; + } + } else { + if (yych <= 'u') { + if (yych <= 'r') goto yy276; + if (yych <= 't') goto yy99; + goto yy280; + } else { + if (yych == 'w') goto yy277; + goto yy99; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == '*') goto yy389; + goto yy99; +yy275: + yych = *++YYCURSOR; + if (yych <= 'm') { + if (yych == 'l') goto yy365; + goto yy99; + } else { + if (yych <= 'n') goto yy366; + if (yych == 'r') goto yy367; + goto yy99; + } +yy276: + yych = *++YYCURSOR; + if (yych == 'e') goto yy359; + goto yy99; +yy277: + yych = *++YYCURSOR; + if (yych == 'a') goto yy352; + goto yy99; +yy278: + yych = *++YYCURSOR; + if (yych == 'r') goto yy346; + goto yy99; +yy279: + yych = *++YYCURSOR; + if (yych == 'i') goto yy342; + goto yy99; +yy280: + yych = *++YYCURSOR; + if (yych == 'n') goto yy337; + goto yy99; +yy281: + yych = *++YYCURSOR; + if (yych == 'e') goto yy331; + goto yy99; +yy282: + yych = *++YYCURSOR; + if (yych == 'f') goto yy290; + if (yych == 'n') goto yy289; + goto yy99; +yy283: + yych = *++YYCURSOR; + if (yych == '?') goto yy286; + goto yy99; +yy284: + ++YYCURSOR; +#line 153 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND); } +#line 3419 "cpp_re.inc" +yy286: + yych = *++YYCURSOR; + if (yych != '=') goto yy99; + ++YYCURSOR; +#line 154 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND_TRIGRAPH); } +#line 3426 "cpp_re.inc" +yy289: + yych = *++YYCURSOR; + if (yych == 'c') goto yy301; + goto yy99; +yy290: + yyaccept = 10; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy293; + if (yych == 'n') goto yy292; +yy291: +#line 301 "cpp.re" + { BOOST_WAVE_RET(T_PP_IF); } +#line 3439 "cpp_re.inc" +yy292: + yych = *++YYCURSOR; + if (yych == 'd') goto yy297; + goto yy99; +yy293: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'f') goto yy99; + ++YYCURSOR; +#line 302 "cpp.re" + { BOOST_WAVE_RET(T_PP_IFDEF); } +#line 3452 "cpp_re.inc" +yy297: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'f') goto yy99; + ++YYCURSOR; +#line 303 "cpp.re" + { BOOST_WAVE_RET(T_PP_IFNDEF); } +#line 3461 "cpp_re.inc" +yy301: + yych = *++YYCURSOR; + if (yych != 'l') goto yy99; + yych = *++YYCURSOR; + if (yych != 'u') goto yy99; + yych = *++YYCURSOR; + if (yych != 'd') goto yy99; + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yyaccept = 11; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '_') goto yy307; + goto yy309; +yy306: +#line 299 "cpp.re" + { BOOST_WAVE_RET(T_PP_INCLUDE); } +#line 3478 "cpp_re.inc" +yy307: + yych = *++YYCURSOR; + if (yych == 'n') goto yy328; + goto yy99; +yy308: + yyaccept = 11; + YYMARKER = ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; +yy309: + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy308; + goto yy306; + } else { + if (yych <= '\f') goto yy308; + if (yych <= 0x1F) goto yy306; + goto yy308; + } + } else { + if (yych <= '.') { + if (yych == '"') goto yy312; + goto yy306; + } else { + if (yych <= '/') goto yy310; + if (yych == '<') goto yy311; + goto yy306; + } + } +yy310: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == '*') goto yy321; + goto yy99; +yy311: + yych = *++YYCURSOR; + if (yych == '>') goto yy99; + goto yy318; +yy312: + yych = *++YYCURSOR; + if (yych == '"') goto yy99; + goto yy314; +yy313: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy314: + if (yybm[0+yych] & 8) { + goto yy313; + } + if (yych <= '!') goto yy99; + ++YYCURSOR; +#line 296 "cpp.re" + { BOOST_WAVE_RET(T_PP_QHEADER); } +#line 3534 "cpp_re.inc" +yy317: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy318: + if (yybm[0+yych] & 16) { + goto yy317; + } + if (yych <= '=') goto yy99; + ++YYCURSOR; +#line 293 "cpp.re" + { BOOST_WAVE_RET(T_PP_HHEADER); } +#line 3547 "cpp_re.inc" +yy321: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy321; + } + if (yych == '\r') goto yy323; + if (yych <= ')') goto yy99; + goto yy325; +yy323: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy321; + } + if (yych == '\r') goto yy323; + if (yych <= ')') goto yy99; +yy325: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy325; + } + if (yych <= '\r') { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy321; + } else { + if (yych <= 0x1F) goto yy99; + if (yych == '/') goto yy308; + goto yy321; + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy321; + } + if (yych == '\r') goto yy323; + if (yych <= ')') goto yy99; + goto yy325; +yy328: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'x') goto yy99; + yych = *++YYCURSOR; + if (yych == 't') goto yy308; + goto yy99; +yy331: + yych = *++YYCURSOR; + if (yych != 'f') goto yy99; + yych = *++YYCURSOR; + if (yych != 'i') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + ++YYCURSOR; +#line 307 "cpp.re" + { BOOST_WAVE_RET(T_PP_DEFINE); } +#line 3611 "cpp_re.inc" +yy337: + yych = *++YYCURSOR; + if (yych != 'd') goto yy99; + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'f') goto yy99; + ++YYCURSOR; +#line 308 "cpp.re" + { BOOST_WAVE_RET(T_PP_UNDEF); } +#line 3622 "cpp_re.inc" +yy342: + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + ++YYCURSOR; +#line 309 "cpp.re" + { BOOST_WAVE_RET(T_PP_LINE); } +#line 3631 "cpp_re.inc" +yy346: + yych = *++YYCURSOR; + if (yych != 'a') goto yy99; + yych = *++YYCURSOR; + if (yych != 'g') goto yy99; + yych = *++YYCURSOR; + if (yych != 'm') goto yy99; + yych = *++YYCURSOR; + if (yych != 'a') goto yy99; + ++YYCURSOR; +#line 311 "cpp.re" + { BOOST_WAVE_RET(T_PP_PRAGMA); } +#line 3644 "cpp_re.inc" +yy352: + yych = *++YYCURSOR; + if (yych != 'r') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + yych = *++YYCURSOR; + if (yych != 'i') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + yych = *++YYCURSOR; + if (yych != 'g') goto yy99; + ++YYCURSOR; +#line 313 "cpp.re" + { BOOST_WAVE_RET(T_PP_WARNING); } +#line 3659 "cpp_re.inc" +yy359: + yych = *++YYCURSOR; + if (yych != 'g') goto yy99; + yych = *++YYCURSOR; + if (yych != 'i') goto yy99; + yych = *++YYCURSOR; + if (yych != 'o') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + ++YYCURSOR; +#line 315 "cpp.re" + { BOOST_WAVE_RET(T_MSEXT_PP_REGION); } +#line 3672 "cpp_re.inc" +yy365: + yych = *++YYCURSOR; + if (yych == 'i') goto yy383; + if (yych == 's') goto yy384; + goto yy99; +yy366: + yych = *++YYCURSOR; + if (yych == 'd') goto yy372; + goto yy99; +yy367: + yych = *++YYCURSOR; + if (yych != 'r') goto yy99; + yych = *++YYCURSOR; + if (yych != 'o') goto yy99; + yych = *++YYCURSOR; + if (yych != 'r') goto yy99; + ++YYCURSOR; +#line 310 "cpp.re" + { BOOST_WAVE_RET(T_PP_ERROR); } +#line 3692 "cpp_re.inc" +yy372: + yych = *++YYCURSOR; + if (yych == 'i') goto yy373; + if (yych == 'r') goto yy374; + goto yy99; +yy373: + yych = *++YYCURSOR; + if (yych == 'f') goto yy381; + goto yy99; +yy374: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + yych = *++YYCURSOR; + if (yych != 'g') goto yy99; + yych = *++YYCURSOR; + if (yych != 'i') goto yy99; + yych = *++YYCURSOR; + if (yych != 'o') goto yy99; + yych = *++YYCURSOR; + if (yych != 'n') goto yy99; + ++YYCURSOR; +#line 316 "cpp.re" + { BOOST_WAVE_RET(T_MSEXT_PP_ENDREGION); } +#line 3716 "cpp_re.inc" +yy381: + ++YYCURSOR; +#line 306 "cpp.re" + { BOOST_WAVE_RET(T_PP_ENDIF); } +#line 3721 "cpp_re.inc" +yy383: + yych = *++YYCURSOR; + if (yych == 'f') goto yy387; + goto yy99; +yy384: + yych = *++YYCURSOR; + if (yych != 'e') goto yy99; + ++YYCURSOR; +#line 304 "cpp.re" + { BOOST_WAVE_RET(T_PP_ELSE); } +#line 3732 "cpp_re.inc" +yy387: + ++YYCURSOR; +#line 305 "cpp.re" + { BOOST_WAVE_RET(T_PP_ELIF); } +#line 3737 "cpp_re.inc" +yy389: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\r') { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy389; + } else { + if (yych <= 0x1F) goto yy99; + if (yych == '*') goto yy393; + goto yy389; + } +yy391: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\r') { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy389; + goto yy391; + } else { + if (yych <= 0x1F) goto yy99; + if (yych != '*') goto yy389; + } +yy393: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy389; + if (yych >= 0x0E) goto yy99; + } else { + if (yych <= '*') { + if (yych <= ')') goto yy389; + goto yy393; + } else { + if (yych == '/') goto yy272; + goto yy389; + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '\r') { + if (yych <= 0x08) goto yy99; + if (yych <= '\f') goto yy389; + goto yy391; + } else { + if (yych <= 0x1F) goto yy99; + if (yych == '*') goto yy393; + goto yy389; + } +yy396: + ++YYCURSOR; +#line 165 "cpp.re" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + BOOST_WAVE_RET(T_COLON); + } + else { + BOOST_WAVE_RET(T_COLON_COLON); + } + } +#line 3803 "cpp_re.inc" +yy398: + ++YYCURSOR; +#line 149 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACKET_ALT); } +#line 3808 "cpp_re.inc" +yy400: + yyaccept = 12; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'e') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy273; + } else { + if (yych <= '\f') goto yy273; + if (yych >= ' ') goto yy273; + } + } else { + if (yych <= '.') { + if (yych == '%') goto yy406; + } else { + if (yych <= '/') goto yy273; + if (yych >= 'd') goto yy273; + } + } + } else { + if (yych <= 'p') { + if (yych <= 'k') { + if (yych == 'i') goto yy273; + } else { + if (yych <= 'l') goto yy273; + if (yych >= 'p') goto yy273; + } + } else { + if (yych <= 't') { + if (yych == 'r') goto yy273; + } else { + if (yych == 'v') goto yy401; + if (yych <= 'w') goto yy273; + } + } + } +yy401: +#line 151 "cpp.re" + { BOOST_WAVE_RET(T_POUND_ALT); } +#line 3848 "cpp_re.inc" +yy402: + ++YYCURSOR; +#line 210 "cpp.re" + { BOOST_WAVE_RET(T_PERCENTASSIGN); } +#line 3853 "cpp_re.inc" +yy404: + ++YYCURSOR; +#line 143 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACE_ALT); } +#line 3858 "cpp_re.inc" +yy406: + yych = *++YYCURSOR; + if (yych != ':') goto yy99; + ++YYCURSOR; +#line 157 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND_ALT); } +#line 3865 "cpp_re.inc" +yy409: + ++YYCURSOR; +#line 226 "cpp.re" + { BOOST_WAVE_RET(T_LESSEQUAL); } +#line 3870 "cpp_re.inc" +yy411: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy417; +#line 219 "cpp.re" + { BOOST_WAVE_RET(T_SHIFTLEFT); } +#line 3876 "cpp_re.inc" +yy413: + ++YYCURSOR; +#line 146 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACKET_ALT); } +#line 3881 "cpp_re.inc" +yy415: + ++YYCURSOR; +#line 140 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACE_ALT); } +#line 3886 "cpp_re.inc" +yy417: + ++YYCURSOR; +#line 222 "cpp.re" + { BOOST_WAVE_RET(T_SHIFTLEFTASSIGN); } +#line 3891 "cpp_re.inc" +yy419: + yych = *++YYCURSOR; + switch (yych) { + case '!': goto yy432; + case '\'': goto yy430; + case '(': goto yy424; + case ')': goto yy426; + case '-': goto yy434; + case '/': goto yy436; + case '<': goto yy420; + case '=': goto yy428; + case '>': goto yy422; + default: goto yy99; + } +yy420: + ++YYCURSOR; +#line 139 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACE_TRIGRAPH); } +#line 3910 "cpp_re.inc" +yy422: + ++YYCURSOR; +#line 142 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACE_TRIGRAPH); } +#line 3915 "cpp_re.inc" +yy424: + ++YYCURSOR; +#line 145 "cpp.re" + { BOOST_WAVE_RET(T_LEFTBRACKET_TRIGRAPH); } +#line 3920 "cpp_re.inc" +yy426: + ++YYCURSOR; +#line 148 "cpp.re" + { BOOST_WAVE_RET(T_RIGHTBRACKET_TRIGRAPH); } +#line 3925 "cpp_re.inc" +yy428: + yyaccept = 13; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'c') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') goto yy273; + } else { + if (yych <= '\f') goto yy273; + if (yych >= ' ') goto yy273; + } + } else { + if (yych <= '.') { + if (yych == '#') goto yy449; + } else { + if (yych <= '/') goto yy273; + if (yych == '?') goto yy448; + } + } + } else { + if (yych <= 'p') { + if (yych <= 'i') { + if (yych <= 'e') goto yy273; + if (yych >= 'i') goto yy273; + } else { + if (yych == 'l') goto yy273; + if (yych >= 'p') goto yy273; + } + } else { + if (yych <= 't') { + if (yych == 'r') goto yy273; + } else { + if (yych == 'v') goto yy429; + if (yych <= 'w') goto yy273; + } + } + } +yy429: +#line 152 "cpp.re" + { BOOST_WAVE_RET(T_POUND_TRIGRAPH); } +#line 3966 "cpp_re.inc" +yy430: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '=') goto yy446; +#line 191 "cpp.re" + { BOOST_WAVE_RET(T_XOR_TRIGRAPH); } +#line 3972 "cpp_re.inc" +yy432: + yyaccept = 14; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '>') { + if (yych == '=') goto yy441; + } else { + if (yych <= '?') goto yy438; + if (yych == '|') goto yy439; + } +yy433: +#line 197 "cpp.re" + { BOOST_WAVE_RET(T_OR_TRIGRAPH); } +#line 3985 "cpp_re.inc" +yy434: + ++YYCURSOR; +#line 199 "cpp.re" + { BOOST_WAVE_RET(T_COMPL_TRIGRAPH); } +#line 3990 "cpp_re.inc" +yy436: + yyaccept = 15; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'U') goto yy100; + if (yych == 'u') goto yy98; +yy437: +#line 249 "cpp.re" + { BOOST_WAVE_RET(T_ANY_TRIGRAPH); } +#line 3999 "cpp_re.inc" +yy438: + yych = *++YYCURSOR; + if (yych == '?') goto yy443; + goto yy99; +yy439: + ++YYCURSOR; +#line 231 "cpp.re" + { BOOST_WAVE_RET(T_OROR_TRIGRAPH); } +#line 4008 "cpp_re.inc" +yy441: + ++YYCURSOR; +#line 218 "cpp.re" + { BOOST_WAVE_RET(T_ORASSIGN_TRIGRAPH); } +#line 4013 "cpp_re.inc" +yy443: + yych = *++YYCURSOR; + if (yych != '!') goto yy99; + ++YYCURSOR; +#line 234 "cpp.re" + { BOOST_WAVE_RET(T_OROR_TRIGRAPH); } +#line 4020 "cpp_re.inc" +yy446: + ++YYCURSOR; +#line 213 "cpp.re" + { BOOST_WAVE_RET(T_XORASSIGN_TRIGRAPH); } +#line 4025 "cpp_re.inc" +yy448: + yych = *++YYCURSOR; + if (yych == '?') goto yy451; + goto yy99; +yy449: + ++YYCURSOR; +#line 155 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND_TRIGRAPH); } +#line 4034 "cpp_re.inc" +yy451: + yych = *++YYCURSOR; + if (yych != '=') goto yy99; + ++YYCURSOR; +#line 156 "cpp.re" + { BOOST_WAVE_RET(T_POUND_POUND_TRIGRAPH); } +#line 4041 "cpp_re.inc" +yy454: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'a': goto yy455; + case 'b': goto yy456; + case 'c': goto yy457; + case 'd': goto yy458; + case 'e': goto yy507; + case 'f': goto yy505; + case 'i': goto yy504; + case 'l': goto yy508; + case 's': goto yy461; + case 't': goto yy506; + default: goto yy109; + } +yy455: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy501; + goto yy109; +yy456: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy496; + goto yy109; +yy457: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy491; + goto yy109; +yy458: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy483; + goto yy109; +yy459: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy475; + goto yy109; +yy460: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy469; + goto yy109; +yy461: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 16; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy468: +#line 130 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_STDCALL : T_IDENTIFIER); } +#line 4117 "cpp_re.inc" +yy469: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; +yy470: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 17; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy474: +#line 135 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INLINE : T_IDENTIFIER); } +#line 4142 "cpp_re.inc" +yy475: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 18; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy482: +#line 129 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_FASTCALL : T_IDENTIFIER); } +#line 4172 "cpp_re.inc" +yy483: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 19; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy490: +#line 127 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_DECLSPEC : T_IDENTIFIER); } +#line 4202 "cpp_re.inc" +yy491: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 20; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy495: +#line 128 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_CDECL : T_IDENTIFIER); } +#line 4223 "cpp_re.inc" +yy496: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 21; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy500: +#line 126 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_BASED : T_IDENTIFIER); } +#line 4244 "cpp_re.inc" +yy501: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'm') goto yy109; + yyaccept = 22; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy503: +#line 136 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_ASM : T_IDENTIFIER); } +#line 4259 "cpp_re.inc" +yy504: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy530; + goto yy109; +yy505: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy475; + if (yych == 'i') goto yy523; + goto yy109; +yy506: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy520; + goto yy109; +yy507: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'x') goto yy514; + goto yy109; +yy508: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'v') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 23; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy513: +#line 134 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_LEAVE : T_IDENTIFIER); } +#line 4304 "cpp_re.inc" +yy514: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 24; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy519: +#line 132 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_EXCEPT : T_IDENTIFIER); } +#line 4328 "cpp_re.inc" +yy520: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'y') goto yy109; + yyaccept = 25; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy522: +#line 131 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_TRY : T_IDENTIFIER); } +#line 4343 "cpp_re.inc" +yy523: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'y') goto yy109; + yyaccept = 26; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy529: +#line 133 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_FINALLY : T_IDENTIFIER); } +#line 4370 "cpp_re.inc" +yy530: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy470; + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case '1': goto yy532; + case '3': goto yy533; + case '6': goto yy534; + case '8': goto yy535; + default: goto yy109; + } +yy532: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '6') goto yy541; + goto yy109; +yy533: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '2') goto yy539; + goto yy109; +yy534: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '4') goto yy537; + goto yy109; +yy535: + yyaccept = 27; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy536: +#line 122 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INT8 : T_IDENTIFIER); } +#line 4411 "cpp_re.inc" +yy537: + yyaccept = 28; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy538: +#line 125 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INT64 : T_IDENTIFIER); } +#line 4423 "cpp_re.inc" +yy539: + yyaccept = 29; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy540: +#line 124 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INT32 : T_IDENTIFIER); } +#line 4435 "cpp_re.inc" +yy541: + yyaccept = 30; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy542: +#line 123 "cpp.re" + { BOOST_WAVE_RET(s->enable_ms_extensions ? T_MSEXT_INT16 : T_IDENTIFIER); } +#line 4447 "cpp_re.inc" +yy543: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'h') goto yy549; + goto yy109; +yy544: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 31; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy548: +#line 120 "cpp.re" + { BOOST_WAVE_RET(T_WHILE); } +#line 4473 "cpp_re.inc" +yy549: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 32; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy554: +#line 119 "cpp.re" + { BOOST_WAVE_RET(T_WCHART); } +#line 4497 "cpp_re.inc" +yy555: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy567; + goto yy109; +yy556: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy557; + if (yych == 'l') goto yy558; + goto yy109; +yy557: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy565; + goto yy109; +yy558: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 33; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy564: +#line 118 "cpp.re" + { BOOST_WAVE_RET(T_VOLATILE); } +#line 4540 "cpp_re.inc" +yy565: + yyaccept = 34; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy566: +#line 117 "cpp.re" + { BOOST_WAVE_RET(T_VOID); } +#line 4552 "cpp_re.inc" +yy567: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 35; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy572: +#line 116 "cpp.re" + { BOOST_WAVE_RET(T_VIRTUAL); } +#line 4576 "cpp_re.inc" +yy573: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '"') goto yy129; + if (yych == 'R') goto yy128; + goto yy109; +yy574: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy580; + if (yych == 's') goto yy581; + goto yy109; +yy575: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'g') goto yy109; + yyaccept = 36; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy579: +#line 115 "cpp.re" + { BOOST_WAVE_RET(T_USING); } +#line 4609 "cpp_re.inc" +yy580: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy588; + goto yy109; +yy581: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'g') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 37; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy587: +#line 114 "cpp.re" + { BOOST_WAVE_RET(T_UNSIGNED); } +#line 4641 "cpp_re.inc" +yy588: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 38; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy590: +#line 113 "cpp.re" + { BOOST_WAVE_RET(T_UNION); } +#line 4656 "cpp_re.inc" +yy591: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'm') goto yy631; + goto yy109; +yy592: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy614; + if (yych == 'r') goto yy615; + goto yy109; +yy593: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy609; + if (yych == 'y') goto yy610; + goto yy109; +yy594: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'h') { + if (yych != 'd') goto yy109; + } else { + if (yych <= 'i') goto yy598; + if (yych == 'n') goto yy599; + goto yy109; + } + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy606; + goto yy109; +yy598: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy604; + goto yy109; +yy599: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'm') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 39; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy603: +#line 112 "cpp.re" + { BOOST_WAVE_RET(T_TYPENAME); } +#line 4719 "cpp_re.inc" +yy604: + yyaccept = 40; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy605: +#line 111 "cpp.re" + { BOOST_WAVE_RET(T_TYPEID); } +#line 4731 "cpp_re.inc" +yy606: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'f') goto yy109; + yyaccept = 41; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy608: +#line 110 "cpp.re" + { BOOST_WAVE_RET(T_TYPEDEF); } +#line 4746 "cpp_re.inc" +yy609: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy612; + goto yy109; +yy610: + yyaccept = 42; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy611: +#line 109 "cpp.re" + { BOOST_WAVE_RET(T_TRY); } +#line 4763 "cpp_re.inc" +yy612: + yyaccept = 43; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy613: +#line 108 "cpp.re" + { BOOST_WAVE_RET(T_TRUE); } +#line 4775 "cpp_re.inc" +yy614: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy629; + goto yy109; +yy615: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy616; + if (yych == 'o') goto yy617; + goto yy109; +yy616: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy620; + goto yy109; +yy617: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'w') goto yy109; + yyaccept = 44; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy619: +#line 107 "cpp.re" + { BOOST_WAVE_RET(T_THROW); } +#line 4806 "cpp_re.inc" +yy620: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 45; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy628: +#line 106 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_THREADLOCAL : T_IDENTIFIER); } +#line 4839 "cpp_re.inc" +yy629: + yyaccept = 46; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy630: +#line 105 "cpp.re" + { BOOST_WAVE_RET(T_THIS); } +#line 4851 "cpp_re.inc" +yy631: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 47; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy637: +#line 104 "cpp.re" + { BOOST_WAVE_RET(T_TEMPLATE); } +#line 4878 "cpp_re.inc" +yy638: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy680; + goto yy109; +yy639: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'g') goto yy670; + if (yych == 'z') goto yy671; + goto yy109; +yy640: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy647; + if (yych == 'r') goto yy648; + goto yy109; +yy641: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'h') goto yy109; + yyaccept = 48; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy646: +#line 103 "cpp.re" + { BOOST_WAVE_RET(T_SWITCH); } +#line 4919 "cpp_re.inc" +yy647: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 't') goto yy653; + goto yy109; +yy648: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 49; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy652: +#line 102 "cpp.re" + { BOOST_WAVE_RET(T_STRUCT); } +#line 4945 "cpp_re.inc" +yy653: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 50; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy657; + if (yych <= '`') goto yy656; + if (yych <= 'z') goto yy108; + } + } +yy656: +#line 99 "cpp.re" + { BOOST_WAVE_RET(T_STATIC); } +#line 4975 "cpp_re.inc" +yy657: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy658; + if (yych == 'c') goto yy659; + goto yy109; +yy658: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy664; + goto yy109; +yy659: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 51; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy663: +#line 100 "cpp.re" + { BOOST_WAVE_RET(T_STATICCAST); } +#line 5007 "cpp_re.inc" +yy664: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 52; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy669: +#line 101 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_STATICASSERT : T_IDENTIFIER); } +#line 5031 "cpp_re.inc" +yy670: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy676; + goto yy109; +yy671: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'f') goto yy109; + yyaccept = 53; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy675: +#line 98 "cpp.re" + { BOOST_WAVE_RET(T_SIZEOF); } +#line 5057 "cpp_re.inc" +yy676: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 54; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy679: +#line 97 "cpp.re" + { BOOST_WAVE_RET(T_SIGNED); } +#line 5075 "cpp_re.inc" +yy680: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 55; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy683: +#line 96 "cpp.re" + { BOOST_WAVE_RET(T_SHORT); } +#line 5093 "cpp_re.inc" +yy684: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'h') { + if (yych != 'g') goto yy109; + } else { + if (yych <= 'i') goto yy686; + if (yych == 't') goto yy687; + goto yy109; + } + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy706; + goto yy109; +yy686: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy692; + goto yy109; +yy687: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 56; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy691: +#line 95 "cpp.re" + { BOOST_WAVE_RET(T_RETURN); } +#line 5133 "cpp_re.inc" +yy692: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 57; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy705: +#line 94 "cpp.re" + { BOOST_WAVE_RET(T_REINTERPRETCAST); } +#line 5181 "cpp_re.inc" +yy706: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 58; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy711: +#line 93 "cpp.re" + { BOOST_WAVE_RET(T_REGISTER); } +#line 5205 "cpp_re.inc" +yy712: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy719; + if (yych == 'o') goto yy720; + goto yy109; +yy713: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'b') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 59; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy718: +#line 92 "cpp.re" + { BOOST_WAVE_RET(T_PUBLIC); } +#line 5235 "cpp_re.inc" +yy719: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'v') goto yy728; + goto yy109; +yy720: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 60; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy727: +#line 91 "cpp.re" + { BOOST_WAVE_RET(T_PROTECTED); } +#line 5270 "cpp_re.inc" +yy728: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 61; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy732: +#line 90 "cpp.re" + { BOOST_WAVE_RET(T_PRIVATE); } +#line 5291 "cpp_re.inc" +yy733: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy740; + goto yy109; +yy734: + yyaccept = 62; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy736; + if (yych <= '`') goto yy735; + if (yych <= 'z') goto yy108; + } + } +yy735: +#line 233 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_OROR_ALT); } +#line 5320 "cpp_re.inc" +yy736: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'q') goto yy109; + yyaccept = 63; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy739: +#line 217 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ORASSIGN_ALT); } +#line 5338 "cpp_re.inc" +yy740: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 64; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy746: +#line 89 "cpp.re" + { BOOST_WAVE_RET(T_OPERATOR); } +#line 5365 "cpp_re.inc" +yy747: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'm') goto yy772; + goto yy109; +yy748: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'w') goto yy770; + goto yy109; +yy749: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy757; + if (yych == 't') goto yy758; + goto yy109; +yy750: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 65; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy756: +#line 88 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_NULLPTR : T_IDENTIFIER); } +#line 5408 "cpp_re.inc" +yy757: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'x') goto yy764; + goto yy109; +yy758: + yyaccept = 66; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy760; + if (yych <= '`') goto yy759; + if (yych <= 'z') goto yy108; + } + } +yy759: +#line 202 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_NOT_ALT); } +#line 5437 "cpp_re.inc" +yy760: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'q') goto yy109; + yyaccept = 67; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy763: +#line 225 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_NOTEQUAL_ALT); } +#line 5455 "cpp_re.inc" +yy764: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 68; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy769: +#line 87 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_NOEXCEPT : T_IDENTIFIER); } +#line 5479 "cpp_re.inc" +yy770: + yyaccept = 69; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy771: +#line 86 "cpp.re" + { BOOST_WAVE_RET(T_NEW); } +#line 5491 "cpp_re.inc" +yy772: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 70; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy779: +#line 85 "cpp.re" + { BOOST_WAVE_RET(T_NAMESPACE); } +#line 5521 "cpp_re.inc" +yy780: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'b') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 71; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy786: +#line 84 "cpp.re" + { BOOST_WAVE_RET(T_MUTABLE); } +#line 5548 "cpp_re.inc" +yy787: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'g') goto yy109; + yyaccept = 72; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy790: +#line 83 "cpp.re" + { BOOST_WAVE_RET(T_LONG); } +#line 5566 "cpp_re.inc" +yy791: + yyaccept = 73; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy792: +#line 79 "cpp.re" + { BOOST_WAVE_RET(T_IF); } +#line 5578 "cpp_re.inc" +yy793: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'p') goto yy802; + goto yy109; +yy794: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy795; + if (yych == 't') goto yy796; + goto yy109; +yy795: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy798; + goto yy109; +yy796: + yyaccept = 74; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy797: +#line 82 "cpp.re" + { BOOST_WAVE_RET(T_INT); } +#line 5606 "cpp_re.inc" +yy798: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 75; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy801: +#line 81 "cpp.re" + { BOOST_WAVE_RET(T_INLINE); } +#line 5624 "cpp_re.inc" +yy802: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 76; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy806: +#line 80 "cpp.re" + { BOOST_WAVE_RET(s->enable_import_keyword ? T_IMPORT : T_IDENTIFIER); } +#line 5645 "cpp_re.inc" +yy807: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 77; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy810: +#line 78 "cpp.re" + { BOOST_WAVE_RET(T_GOTO); } +#line 5663 "cpp_re.inc" +yy811: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy826; + goto yy109; +yy812: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy822; + goto yy109; +yy813: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy820; + goto yy109; +yy814: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 78; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy819: +#line 77 "cpp.re" + { BOOST_WAVE_RET(T_FRIEND); } +#line 5702 "cpp_re.inc" +yy820: + yyaccept = 79; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy821: +#line 76 "cpp.re" + { BOOST_WAVE_RET(T_FOR); } +#line 5714 "cpp_re.inc" +yy822: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 80; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy825: +#line 75 "cpp.re" + { BOOST_WAVE_RET(T_FLOAT); } +#line 5732 "cpp_re.inc" +yy826: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 81; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy829: +#line 74 "cpp.re" + { BOOST_WAVE_RET(T_FALSE); } +#line 5750 "cpp_re.inc" +yy830: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy852; + goto yy109; +yy831: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy849; + goto yy109; +yy832: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'p') goto yy833; + if (yych == 't') goto yy834; + goto yy109; +yy833: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy839; + if (yych == 'o') goto yy840; + goto yy109; +yy834: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 82; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy838: +#line 73 "cpp.re" + { BOOST_WAVE_RET(T_EXTERN); } +#line 5793 "cpp_re.inc" +yy839: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy844; + goto yy109; +yy840: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 83; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy843: +#line 72 "cpp.re" + { BOOST_WAVE_RET(T_EXPORT); } +#line 5816 "cpp_re.inc" +yy844: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 84; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy848: +#line 71 "cpp.re" + { BOOST_WAVE_RET(T_EXPLICIT); } +#line 5837 "cpp_re.inc" +yy849: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'm') goto yy109; + yyaccept = 85; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy851: +#line 70 "cpp.re" + { BOOST_WAVE_RET(T_ENUM); } +#line 5852 "cpp_re.inc" +yy852: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 86; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy854: +#line 69 "cpp.re" + { BOOST_WAVE_RET(T_ELSE); } +#line 5867 "cpp_re.inc" +yy855: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'e') { + if (yych == 'c') goto yy875; + goto yy109; + } else { + if (yych <= 'f') goto yy876; + if (yych == 'l') goto yy877; + goto yy109; + } +yy856: + yyaccept = 87; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'Z') { + if (yych <= '9') { + if (yych == '$') goto yy108; + if (yych >= '0') goto yy108; + } else { + if (yych == '?') goto yy111; + if (yych >= 'A') goto yy108; + } + } else { + if (yych <= '_') { + if (yych == '\\') goto yy110; + if (yych >= '_') goto yy108; + } else { + if (yych <= 't') { + if (yych >= 'a') goto yy108; + } else { + if (yych <= 'u') goto yy870; + if (yych <= 'z') goto yy108; + } + } + } +yy857: +#line 66 "cpp.re" + { BOOST_WAVE_RET(T_DO); } +#line 5906 "cpp_re.inc" +yy858: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'm') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 88; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy869: +#line 68 "cpp.re" + { BOOST_WAVE_RET(T_DYNAMICCAST); } +#line 5948 "cpp_re.inc" +yy870: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'b') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 89; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy874: +#line 67 "cpp.re" + { BOOST_WAVE_RET(T_DOUBLE); } +#line 5969 "cpp_re.inc" +yy875: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'l') goto yy887; + goto yy109; +yy876: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy882; + goto yy109; +yy877: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 90; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy881: +#line 65 "cpp.re" + { BOOST_WAVE_RET(T_DELETE); } +#line 6000 "cpp_re.inc" +yy882: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 91; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy886: +#line 64 "cpp.re" + { BOOST_WAVE_RET(T_DEFAULT); } +#line 6021 "cpp_re.inc" +yy887: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'y') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 92; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy892: +#line 63 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_DECLTYPE : T_IDENTIFIER); } +#line 6045 "cpp_re.inc" +yy893: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'r') goto yy109; + if (yych <= 's') goto yy939; + if (yych <= 't') goto yy940; + goto yy109; +yy894: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy926; + goto yy109; +yy895: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy922; + goto yy109; +yy896: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'l') goto yy109; + if (yych <= 'm') goto yy898; + if (yych >= 'o') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'r') goto yy109; + if (yych <= 's') goto yy902; + if (yych <= 't') goto yy903; + goto yy109; +yy898: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 93; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy901: +#line 200 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_COMPL_ALT); } +#line 6092 "cpp_re.inc" +yy902: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 't') goto yy909; + goto yy109; +yy903: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'i') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'u') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 94; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy908: +#line 62 "cpp.re" + { BOOST_WAVE_RET(T_CONTINUE); } +#line 6121 "cpp_re.inc" +yy909: + yyaccept = 95; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'Z') { + if (yych <= '9') { + if (yych == '$') goto yy108; + if (yych >= '0') goto yy108; + } else { + if (yych == '?') goto yy111; + if (yych >= 'A') goto yy108; + } + } else { + if (yych <= '_') { + if (yych == '\\') goto yy110; + if (yych >= '_') goto yy911; + } else { + if (yych <= 'd') { + if (yych >= 'a') goto yy108; + } else { + if (yych <= 'e') goto yy912; + if (yych <= 'z') goto yy108; + } + } + } +yy910: +#line 59 "cpp.re" + { BOOST_WAVE_RET(T_CONST); } +#line 6149 "cpp_re.inc" +yy911: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'c') goto yy917; + goto yy109; +yy912: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'x') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'p') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 96; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy916: +#line 60 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_CONSTEXPR : T_IDENTIFIER); } +#line 6175 "cpp_re.inc" +yy917: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 97; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy921: +#line 61 "cpp.re" + { BOOST_WAVE_RET(T_CONSTCAST); } +#line 6196 "cpp_re.inc" +yy922: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 's') goto yy109; + yyaccept = 98; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy925: +#line 58 "cpp.re" + { BOOST_WAVE_RET(T_CLASS); } +#line 6214 "cpp_re.inc" +yy926: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 99; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '>') { + if (yych <= '0') { + if (yych == '$') goto yy108; + if (yych >= '0') goto yy108; + } else { + if (yych <= '2') { + if (yych <= '1') goto yy929; + goto yy108; + } else { + if (yych <= '3') goto yy930; + if (yych <= '9') goto yy108; + } + } + } else { + if (yych <= '\\') { + if (yych <= '@') { + if (yych <= '?') goto yy111; + } else { + if (yych <= 'Z') goto yy108; + if (yych >= '\\') goto yy110; + } + } else { + if (yych <= '_') { + if (yych >= '_') goto yy108; + } else { + if (yych <= '`') goto yy928; + if (yych <= 'z') goto yy108; + } + } + } +yy928: +#line 55 "cpp.re" + { BOOST_WAVE_RET(T_CHAR); } +#line 6254 "cpp_re.inc" +yy929: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '6') goto yy935; + goto yy109; +yy930: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '2') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 100; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy934: +#line 57 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_CHAR32_T : T_IDENTIFIER); } +#line 6280 "cpp_re.inc" +yy935: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '_') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 101; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy938: +#line 56 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_CHAR16_T : T_IDENTIFIER); } +#line 6298 "cpp_re.inc" +yy939: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'e') goto yy944; + goto yy109; +yy940: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'c') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'h') goto yy109; + yyaccept = 102; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy943: +#line 54 "cpp.re" + { BOOST_WAVE_RET(T_CATCH); } +#line 6321 "cpp_re.inc" +yy944: + yyaccept = 103; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy945: +#line 53 "cpp.re" + { BOOST_WAVE_RET(T_CASE); } +#line 6333 "cpp_re.inc" +yy946: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 't') goto yy956; + goto yy109; +yy947: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'o') goto yy953; + goto yy109; +yy948: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'a') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'k') goto yy109; + yyaccept = 104; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy952: +#line 52 "cpp.re" + { BOOST_WAVE_RET(T_BREAK); } +#line 6364 "cpp_re.inc" +yy953: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'l') goto yy109; + yyaccept = 105; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy955: +#line 51 "cpp.re" + { BOOST_WAVE_RET(T_BOOL); } +#line 6379 "cpp_re.inc" +yy956: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy957; + if (yych == 'o') goto yy958; + goto yy109; +yy957: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'n') goto yy961; + goto yy109; +yy958: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'r') goto yy109; + yyaccept = 106; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy960: +#line 196 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_OR_ALT); } +#line 6405 "cpp_re.inc" +yy961: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'd') goto yy109; + yyaccept = 107; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy963: +#line 194 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_AND_ALT); } +#line 6420 "cpp_re.inc" +yy964: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'i') goto yy979; + goto yy109; +yy965: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'd') goto yy973; + goto yy109; +yy966: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'm') goto yy971; + goto yy109; +yy967: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 't') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'o') goto yy109; + yyaccept = 108; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy970: +#line 50 "cpp.re" + { BOOST_WAVE_RET(T_AUTO); } +#line 6453 "cpp_re.inc" +yy971: + yyaccept = 109; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy972: +#line 49 "cpp.re" + { BOOST_WAVE_RET(T_ASM); } +#line 6465 "cpp_re.inc" +yy973: + yyaccept = 110; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '@') { + if (yych <= '/') { + if (yych == '$') goto yy108; + } else { + if (yych <= '9') goto yy108; + if (yych == '?') goto yy111; + } + } else { + if (yych <= '^') { + if (yych <= 'Z') goto yy108; + if (yych == '\\') goto yy110; + } else { + if (yych <= '_') goto yy975; + if (yych <= '`') goto yy974; + if (yych <= 'z') goto yy108; + } + } +yy974: +#line 229 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ANDAND_ALT); } +#line 6489 "cpp_re.inc" +yy975: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'e') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'q') goto yy109; + yyaccept = 111; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy978: +#line 215 "cpp.re" + { BOOST_WAVE_RET(s->act_in_c99_mode ? T_IDENTIFIER : T_ANDASSIGN_ALT); } +#line 6507 "cpp_re.inc" +yy979: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'g') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'n') goto yy109; + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy982; + if (yych == 'o') goto yy983; + goto yy109; +yy982: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 's') goto yy986; + goto yy109; +yy983: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != 'f') goto yy109; + yyaccept = 112; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy985: +#line 48 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_ALIGNOF : T_IDENTIFIER); } +#line 6539 "cpp_re.inc" +yy986: + yyaccept = 113; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[256+yych] & 32) { + goto yy108; + } + if (yych == '?') goto yy111; + if (yych == '\\') goto yy110; +yy987: +#line 47 "cpp.re" + { BOOST_WAVE_RET(s->act_in_cpp0x_mode ? T_ALIGNAS : T_IDENTIFIER); } +#line 6551 "cpp_re.inc" +yy988: + ++YYCURSOR; +#line 176 "cpp.re" + { + if (s->act_in_c99_mode) { + --YYCURSOR; + BOOST_WAVE_RET(T_DOT); + } + else { + BOOST_WAVE_RET(T_DOTSTAR); + } + } +#line 6564 "cpp_re.inc" +yy990: + yych = *++YYCURSOR; + if (yych == '.') goto yy992; + goto yy99; +yy991: + yych = *++YYCURSOR; + goto yy7; +yy992: + ++YYCURSOR; +#line 162 "cpp.re" + { BOOST_WAVE_RET(T_ELLIPSIS); } +#line 6576 "cpp_re.inc" +yy994: + ++YYCURSOR; +#line 209 "cpp.re" + { BOOST_WAVE_RET(T_DIVIDEASSIGN); } +#line 6581 "cpp_re.inc" +yy996: + ++YYCURSOR; +#line 44 "cpp.re" + { goto cppcomment; } +#line 6586 "cpp_re.inc" +yy998: + ++YYCURSOR; +#line 43 "cpp.re" + { goto ccomment; } +#line 6591 "cpp_re.inc" +} +#line 348 "cpp.re" + + +ccomment: + +#line 6598 "cpp_re.inc" +{ + YYCTYPE yych; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= '\f') { + if (yych <= 0x08) { + if (yych <= 0x00) goto yy1009; + goto yy1011; + } else { + if (yych == '\n') goto yy1004; + goto yy1007; + } + } else { + if (yych <= 0x1F) { + if (yych <= '\r') goto yy1006; + goto yy1011; + } else { + if (yych != '*') goto yy1008; + } + } + ++YYCURSOR; + if ((yych = *YYCURSOR) == '/') goto yy1014; +yy1003: +#line 363 "cpp.re" + { goto ccomment; } +#line 6624 "cpp_re.inc" +yy1004: + ++YYCURSOR; +yy1005: +#line 355 "cpp.re" + { + /*if(cursor == s->eof) BOOST_WAVE_RET(T_EOF);*/ + /*s->tok = cursor; */ + s->line += count_backslash_newlines(s, cursor) +1; + cursor.column = 1; + goto ccomment; + } +#line 6636 "cpp_re.inc" +yy1006: + yych = *++YYCURSOR; + if (yych == '\n') goto yy1013; + goto yy1005; +yy1007: + yych = *++YYCURSOR; + goto yy1003; +yy1008: + yych = *++YYCURSOR; + goto yy1003; +yy1009: + ++YYCURSOR; +#line 366 "cpp.re" + { + if(cursor == s->eof) + { + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_warning, + "Unterminated 'C' style comment"); + } + else + { + --YYCURSOR; // next call returns T_EOF + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character: '\\000' in input stream"); + } + } +#line 6665 "cpp_re.inc" +yy1011: + ++YYCURSOR; +#line 383 "cpp.re" + { + // flag the error + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\%03o' in input stream", *--YYCURSOR); + } +#line 6675 "cpp_re.inc" +yy1013: + yych = *++YYCURSOR; + goto yy1005; +yy1014: + ++YYCURSOR; +#line 352 "cpp.re" + { BOOST_WAVE_RET(T_CCOMMENT); } +#line 6683 "cpp_re.inc" +} +#line 389 "cpp.re" + + +cppcomment: + +#line 6690 "cpp_re.inc" +{ + YYCTYPE yych; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= '\n') { + if (yych <= 0x00) goto yy1024; + if (yych <= 0x08) goto yy1026; + if (yych <= '\t') goto yy1021; + } else { + if (yych <= '\f') goto yy1021; + if (yych <= '\r') goto yy1020; + if (yych <= 0x1F) goto yy1026; + goto yy1023; + } + ++YYCURSOR; +yy1019: +#line 394 "cpp.re" + { + /*if(cursor == s->eof) BOOST_WAVE_RET(T_EOF); */ + /*s->tok = cursor; */ + s->line++; + cursor.column = 1; + BOOST_WAVE_RET(T_CPPCOMMENT); + } +#line 6715 "cpp_re.inc" +yy1020: + yych = *++YYCURSOR; + if (yych == '\n') goto yy1028; + goto yy1019; +yy1021: + ++YYCURSOR; +yy1022: +#line 402 "cpp.re" + { goto cppcomment; } +#line 6725 "cpp_re.inc" +yy1023: + yych = *++YYCURSOR; + goto yy1022; +yy1024: + ++YYCURSOR; +#line 405 "cpp.re" + { + if (s->eof && cursor != s->eof) + { + --YYCURSOR; // next call returns T_EOF + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\000' in input stream"); + } + + --YYCURSOR; // next call returns T_EOF + if (!s->single_line_only) + { + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_warning, + "Unterminated 'C++' style comment"); + } + BOOST_WAVE_RET(T_CPPCOMMENT); + } +#line 6750 "cpp_re.inc" +yy1026: + ++YYCURSOR; +#line 425 "cpp.re" + { + // flag the error + BOOST_WAVE_UPDATE_CURSOR(); // adjust the input cursor + (*s->error_proc)(s, lexing_exception::generic_lexing_error, + "invalid character '\\%03o' in input stream", *--YYCURSOR); + } +#line 6760 "cpp_re.inc" +yy1028: + ++YYCURSOR; + yych = *YYCURSOR; + goto yy1019; +} +#line 431 "cpp.re" + + +/* this subscanner is called whenever a pp_number has been started */ +pp_number: +{ + cursor = uchar_wrapper(s->tok = s->cur, s->column = s->curr_column); + marker = uchar_wrapper(s->ptr); + limit = uchar_wrapper(s->lim); + + if (s->detect_pp_numbers) { + +#line 6778 "cpp_re.inc" +{ + YYCTYPE yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 64, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 64, 0, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 0, 0, 0, 0, 0, 0, + 0, 64, 64, 64, 64, 128, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 0, 0, 0, 0, 64, + 0, 64, 64, 64, 64, 128, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych == '.') goto yy1032; + if (yych <= '/') goto yy1031; + if (yych <= '9') goto yy1033; +yy1031: + YYCURSOR = YYMARKER; + goto yy1035; +yy1032: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; +yy1033: + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy1033; + } + if (yych <= 'Z') { + if (yych == '?') goto yy1039; + if (yych >= 'A') goto yy1036; + } else { + if (yych <= '\\') { + if (yych >= '\\') goto yy1038; + } else { + if (yych == 'e') goto yy1036; + } + } +yy1035: +#line 443 "cpp.re" + { BOOST_WAVE_RET(T_PP_NUMBER); } +#line 6847 "cpp_re.inc" +yy1036: + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1036; + } + if (yych <= '>') { + if (yych <= '+') { + if (yych == '$') goto yy1033; + if (yych <= '*') goto yy1035; + goto yy1033; + } else { + if (yych <= '.') { + if (yych <= ',') goto yy1035; + goto yy1033; + } else { + if (yych <= '/') goto yy1035; + if (yych <= '9') goto yy1033; + goto yy1035; + } + } + } else { + if (yych <= '\\') { + if (yych <= '@') { + if (yych <= '?') goto yy1039; + goto yy1035; + } else { + if (yych <= 'Z') goto yy1033; + if (yych <= '[') goto yy1035; + } + } else { + if (yych <= '_') { + if (yych <= '^') goto yy1035; + goto yy1033; + } else { + if (yych <= '`') goto yy1035; + if (yych <= 'z') goto yy1033; + goto yy1035; + } + } + } +yy1038: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == 'U') goto yy1042; + if (yych == 'u') goto yy1041; + goto yy1031; +yy1039: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych != '?') goto yy1031; + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych == '/') goto yy1038; + goto yy1031; +yy1041: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych <= '9') goto yy1050; + goto yy1031; + } else { + if (yych <= 'F') goto yy1050; + if (yych <= '`') goto yy1031; + if (yych <= 'f') goto yy1050; + goto yy1031; + } +yy1042: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1043; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1043: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1044; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1044: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1045; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1045: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1046; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1046: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1047; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1047: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1048; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1048: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1049; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1049: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych <= '9') goto yy1033; + goto yy1031; + } else { + if (yych <= 'F') goto yy1033; + if (yych <= '`') goto yy1031; + if (yych <= 'f') goto yy1033; + goto yy1031; + } +yy1050: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1051; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1051: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych >= ':') goto yy1031; + } else { + if (yych <= 'F') goto yy1052; + if (yych <= '`') goto yy1031; + if (yych >= 'g') goto yy1031; + } +yy1052: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1031; + if (yych <= '9') goto yy1033; + goto yy1031; + } else { + if (yych <= 'F') goto yy1033; + if (yych <= '`') goto yy1031; + if (yych <= 'f') goto yy1033; + goto yy1031; + } +} +#line 444 "cpp.re" + + } + else { + +#line 7063 "cpp_re.inc" +{ + YYCTYPE yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 224, 224, 224, 224, 224, 224, 224, 224, + 160, 160, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; + if (yych <= '/') { + if (yych == '.') goto yy1060; + } else { + if (yych <= '0') goto yy1056; + if (yych <= '9') goto yy1058; + } +yy1055: + YYCURSOR = YYMARKER; + if (yyaccept <= 0) { + goto yy1057; + } else { + goto yy1063; + } +yy1056: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 64) { + goto yy1075; + } + if (yych <= 'E') { + if (yych <= '/') { + if (yych == '.') goto yy1061; + } else { + if (yych <= '9') goto yy1078; + if (yych >= 'E') goto yy1071; + } + } else { + if (yych <= 'd') { + if (yych == 'X') goto yy1077; + } else { + if (yych <= 'e') goto yy1071; + if (yych == 'x') goto yy1077; + } + } +yy1057: +#line 451 "cpp.re" + { goto integer_suffix; } +#line 7140 "cpp_re.inc" +yy1058: + yyaccept = 0; + YYMARKER = ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy1058; + } + if (yych <= 'D') { + if (yych == '.') goto yy1061; + goto yy1057; + } else { + if (yych <= 'E') goto yy1071; + if (yych == 'e') goto yy1071; + goto yy1057; + } +yy1060: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1055; + if (yych >= ':') goto yy1055; +yy1061: + yyaccept = 1; + YYMARKER = ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yych <= 'K') { + if (yych <= 'D') { + if (yych <= '/') goto yy1063; + if (yych <= '9') goto yy1061; + } else { + if (yych <= 'E') goto yy1064; + if (yych <= 'F') goto yy1065; + } + } else { + if (yych <= 'e') { + if (yych <= 'L') goto yy1066; + if (yych >= 'e') goto yy1064; + } else { + if (yych <= 'f') goto yy1065; + if (yych == 'l') goto yy1066; + } + } +yy1063: +#line 449 "cpp.re" + { BOOST_WAVE_RET(T_FLOATLIT); } +#line 7186 "cpp_re.inc" +yy1064: + yych = *++YYCURSOR; + if (yych <= ',') { + if (yych == '+') goto yy1068; + goto yy1055; + } else { + if (yych <= '-') goto yy1068; + if (yych <= '/') goto yy1055; + if (yych <= '9') goto yy1069; + goto yy1055; + } +yy1065: + yych = *++YYCURSOR; + if (yych == 'L') goto yy1067; + if (yych == 'l') goto yy1067; + goto yy1063; +yy1066: + yych = *++YYCURSOR; + if (yych == 'F') goto yy1067; + if (yych != 'f') goto yy1063; +yy1067: + yych = *++YYCURSOR; + goto yy1063; +yy1068: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1055; + if (yych >= ':') goto yy1055; +yy1069: + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= 'K') { + if (yych <= '9') { + if (yych <= '/') goto yy1063; + goto yy1069; + } else { + if (yych == 'F') goto yy1065; + goto yy1063; + } + } else { + if (yych <= 'f') { + if (yych <= 'L') goto yy1066; + if (yych <= 'e') goto yy1063; + goto yy1065; + } else { + if (yych == 'l') goto yy1066; + goto yy1063; + } + } +yy1071: + yych = *++YYCURSOR; + if (yych <= ',') { + if (yych != '+') goto yy1055; + } else { + if (yych <= '-') goto yy1072; + if (yych <= '/') goto yy1055; + if (yych <= '9') goto yy1073; + goto yy1055; + } +yy1072: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1055; + if (yych >= ':') goto yy1055; +yy1073: + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= 'K') { + if (yych <= '9') { + if (yych <= '/') goto yy1063; + goto yy1073; + } else { + if (yych == 'F') goto yy1065; + goto yy1063; + } + } else { + if (yych <= 'f') { + if (yych <= 'L') goto yy1066; + if (yych <= 'e') goto yy1063; + goto yy1065; + } else { + if (yych == 'l') goto yy1066; + goto yy1063; + } + } +yy1075: + yyaccept = 0; + YYMARKER = ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy1075; + } + if (yych <= '9') { + if (yych == '.') goto yy1061; + if (yych <= '/') goto yy1057; + goto yy1078; + } else { + if (yych <= 'E') { + if (yych <= 'D') goto yy1057; + goto yy1071; + } else { + if (yych == 'e') goto yy1071; + goto yy1057; + } + } +yy1077: + yych = *++YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1080; + } + goto yy1055; +yy1078: + ++YYCURSOR; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych == '.') goto yy1061; + if (yych <= '/') goto yy1055; + goto yy1078; + } else { + if (yych <= 'E') { + if (yych <= 'D') goto yy1055; + goto yy1071; + } else { + if (yych == 'e') goto yy1071; + goto yy1055; + } + } +yy1080: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1080; + } + goto yy1057; +} +#line 452 "cpp.re" + + } +} + +/* this subscanner is called, whenever an Integer was recognized */ +integer_suffix: +{ + if (s->enable_ms_extensions) { + +#line 7335 "cpp_re.inc" +{ + YYCTYPE yych; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *(YYMARKER = YYCURSOR); + if (yych <= 'h') { + if (yych <= 'L') { + if (yych >= 'L') goto yy1086; + } else { + if (yych == 'U') goto yy1085; + } + } else { + if (yych <= 'l') { + if (yych <= 'i') goto yy1087; + if (yych >= 'l') goto yy1086; + } else { + if (yych == 'u') goto yy1085; + } + } +yy1084: +#line 465 "cpp.re" + { BOOST_WAVE_RET(T_INTLIT); } +#line 7357 "cpp_re.inc" +yy1085: + yych = *++YYCURSOR; + if (yych == 'L') goto yy1094; + if (yych == 'l') goto yy1094; + goto yy1084; +yy1086: + yych = *++YYCURSOR; + if (yych <= 'U') { + if (yych == 'L') goto yy1093; + if (yych <= 'T') goto yy1084; + goto yy1092; + } else { + if (yych <= 'l') { + if (yych <= 'k') goto yy1084; + goto yy1093; + } else { + if (yych == 'u') goto yy1092; + goto yy1084; + } + } +yy1087: + yych = *++YYCURSOR; + if (yych == '6') goto yy1089; +yy1088: + YYCURSOR = YYMARKER; + goto yy1084; +yy1089: + yych = *++YYCURSOR; + if (yych != '4') goto yy1088; +yy1090: + ++YYCURSOR; +yy1091: +#line 462 "cpp.re" + { BOOST_WAVE_RET(T_LONGINTLIT); } +#line 7392 "cpp_re.inc" +yy1092: + yych = *++YYCURSOR; + goto yy1084; +yy1093: + yych = *++YYCURSOR; + if (yych == 'U') goto yy1090; + if (yych == 'u') goto yy1090; + goto yy1091; +yy1094: + ++YYCURSOR; + if ((yych = *YYCURSOR) == 'L') goto yy1090; + if (yych == 'l') goto yy1090; + goto yy1084; +} +#line 466 "cpp.re" + + } + else { + +#line 7412 "cpp_re.inc" +{ + YYCTYPE yych; + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + if (yych <= 'U') { + if (yych == 'L') goto yy1099; + if (yych >= 'U') goto yy1098; + } else { + if (yych <= 'l') { + if (yych >= 'l') goto yy1099; + } else { + if (yych == 'u') goto yy1098; + } + } +yy1097: +#line 474 "cpp.re" + { BOOST_WAVE_RET(T_INTLIT); } +#line 7430 "cpp_re.inc" +yy1098: + yych = *++YYCURSOR; + if (yych == 'L') goto yy1104; + if (yych == 'l') goto yy1104; + goto yy1097; +yy1099: + yych = *++YYCURSOR; + if (yych <= 'U') { + if (yych == 'L') goto yy1101; + if (yych <= 'T') goto yy1097; + } else { + if (yych <= 'l') { + if (yych <= 'k') goto yy1097; + goto yy1101; + } else { + if (yych != 'u') goto yy1097; + } + } + yych = *++YYCURSOR; + goto yy1097; +yy1101: + ++YYCURSOR; + if ((yych = *YYCURSOR) == 'U') goto yy1103; + if (yych == 'u') goto yy1103; +yy1102: +#line 471 "cpp.re" + { BOOST_WAVE_RET(T_LONGINTLIT); } +#line 7458 "cpp_re.inc" +yy1103: + yych = *++YYCURSOR; + goto yy1102; +yy1104: + ++YYCURSOR; + if ((yych = *YYCURSOR) == 'L') goto yy1103; + if (yych == 'l') goto yy1103; + goto yy1097; +} +#line 475 "cpp.re" + + } +} + +/* this subscanner is invoked for C++0x extended character literals */ +extcharlit: +{ + +#line 7477 "cpp_re.inc" +{ + YYCTYPE yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((YYLIMIT - YYCURSOR) < 13) YYFILL(13); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x08) goto yy1107; + if (yych <= '\t') goto yy1108; + goto yy1112; + } else { + if (yych <= '\f') goto yy1108; + if (yych <= '\r') goto yy1112; + } + } else { + if (yych <= '>') { + if (yych == '\'') goto yy1112; + goto yy1108; + } else { + if (yych <= '?') goto yy1110; + if (yych == '\\') goto yy1111; + goto yy1108; + } + } +yy1107: + YYCURSOR = YYMARKER; + goto yy1109; +yy1108: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '\'') goto yy1120; +yy1109: +#line 487 "cpp.re" + { BOOST_WAVE_RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); } +#line 7544 "cpp_re.inc" +yy1110: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '\'') goto yy1120; + if (yych == '?') goto yy1135; + goto yy1109; +yy1111: + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1115; + goto yy1109; + } else { + if (yych <= '\'') goto yy1115; + if (yych <= '/') goto yy1109; + goto yy1118; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1116; + goto yy1109; + } else { + if (yych <= 'U') goto yy1114; + if (yych == '\\') goto yy1115; + goto yy1109; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1115; + if (yych <= 'e') goto yy1109; + goto yy1115; + } else { + if (yych == 'n') goto yy1115; + if (yych <= 'q') goto yy1109; + goto yy1115; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1109; + if (yych <= 't') goto yy1115; + goto yy1113; + } else { + if (yych <= 'v') goto yy1115; + if (yych == 'x') goto yy1117; + goto yy1109; + } + } + } +yy1112: + yych = *++YYCURSOR; + goto yy1109; +yy1113: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych <= '9') goto yy1132; + goto yy1107; + } else { + if (yych <= 'F') goto yy1132; + if (yych <= '`') goto yy1107; + if (yych <= 'f') goto yy1132; + goto yy1107; + } +yy1114: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych <= '9') goto yy1125; + goto yy1107; + } else { + if (yych <= 'F') goto yy1125; + if (yych <= '`') goto yy1107; + if (yych <= 'f') goto yy1125; + goto yy1107; + } +yy1115: + yych = *++YYCURSOR; + if (yych == '\'') goto yy1120; + goto yy1107; +yy1116: + yych = *++YYCURSOR; + if (yych == '\'') goto yy1120; + if (yych == '?') goto yy1124; + goto yy1107; +yy1117: + yych = *++YYCURSOR; + if (yych == '\'') goto yy1107; + goto yy1123; +yy1118: + yych = *++YYCURSOR; + if (yych == '\'') goto yy1120; + if (yych <= '/') goto yy1107; + if (yych >= '8') goto yy1107; + yych = *++YYCURSOR; + if (yych == '\'') goto yy1120; + if (yych <= '/') goto yy1107; + if (yych <= '7') goto yy1115; + goto yy1107; +yy1120: + ++YYCURSOR; +#line 484 "cpp.re" + { BOOST_WAVE_RET(T_CHARLIT); } +#line 7649 "cpp_re.inc" +yy1122: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy1123: + if (yybm[0+yych] & 128) { + goto yy1122; + } + if (yych == '\'') goto yy1120; + goto yy1107; +yy1124: + yych = *++YYCURSOR; + if (yych == '/') goto yy1115; + goto yy1107; +yy1125: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1126; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1126: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1127; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1127: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1128; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1128: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1129; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1129: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1130; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1130: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1131; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1131: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych <= '9') goto yy1115; + goto yy1107; + } else { + if (yych <= 'F') goto yy1115; + if (yych <= '`') goto yy1107; + if (yych <= 'f') goto yy1115; + goto yy1107; + } +yy1132: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1133; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1133: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych >= ':') goto yy1107; + } else { + if (yych <= 'F') goto yy1134; + if (yych <= '`') goto yy1107; + if (yych >= 'g') goto yy1107; + } +yy1134: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1107; + if (yych <= '9') goto yy1115; + goto yy1107; + } else { + if (yych <= 'F') goto yy1115; + if (yych <= '`') goto yy1107; + if (yych <= 'f') goto yy1115; + goto yy1107; + } +yy1135: + yych = *++YYCURSOR; + if (yych != '/') goto yy1107; + ++YYCURSOR; + if ((yych = *YYCURSOR) <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1115; + goto yy1107; + } else { + if (yych <= '\'') goto yy1115; + if (yych <= '/') goto yy1107; + goto yy1118; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1116; + goto yy1107; + } else { + if (yych <= 'U') goto yy1114; + if (yych == '\\') goto yy1115; + goto yy1107; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1115; + if (yych <= 'e') goto yy1107; + goto yy1115; + } else { + if (yych == 'n') goto yy1115; + if (yych <= 'q') goto yy1107; + goto yy1115; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1107; + if (yych <= 't') goto yy1115; + goto yy1113; + } else { + if (yych <= 'v') goto yy1115; + if (yych == 'x') goto yy1117; + goto yy1107; + } + } + } +} +#line 488 "cpp.re" + +} + +/* this subscanner is invoked for C++0x extended character string literals */ +extstringlit: +{ + +#line 7824 "cpp_re.inc" +{ + YYCTYPE yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 16, 0, 16, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 16, 0, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 144, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 16, 16, 16, 16, 16, 32, + 16, 144, 144, 144, 144, 144, 144, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 64, 16, 16, 16, + 16, 144, 144, 144, 144, 144, 144, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + }; + if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x08) goto yy1139; + if (yych <= '\t') goto yy1140; + goto yy1146; + } else { + if (yych <= '\f') goto yy1140; + if (yych <= '\r') goto yy1146; + } + } else { + if (yych <= '>') { + if (yych == '"') goto yy1144; + goto yy1140; + } else { + if (yych <= '?') goto yy1142; + if (yych == '\\') goto yy1143; + goto yy1140; + } + } +yy1139: + YYCURSOR = YYMARKER; + if (yyaccept <= 0) { + goto yy1141; + } else { + goto yy1145; + } +yy1140: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\n') { + if (yych == '\t') goto yy1150; + } else { + if (yych <= '\f') goto yy1150; + if (yych >= ' ') goto yy1150; + } +yy1141: +#line 499 "cpp.re" + { BOOST_WAVE_RET(TOKEN_FROM_ID(*s->tok, UnknownTokenType)); } +#line 7902 "cpp_re.inc" +yy1142: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yybm[0+yych] & 32) { + goto yy1158; + } + if (yych <= '\n') { + if (yych == '\t') goto yy1150; + goto yy1141; + } else { + if (yych <= '\f') goto yy1150; + if (yych <= 0x1F) goto yy1141; + goto yy1150; + } +yy1143: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1149; + goto yy1141; + } else { + if (yych <= '\'') goto yy1149; + if (yych <= '/') goto yy1141; + goto yy1153; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1151; + goto yy1141; + } else { + if (yych <= 'U') goto yy1148; + if (yych == '\\') goto yy1149; + goto yy1141; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1149; + if (yych <= 'e') goto yy1141; + goto yy1149; + } else { + if (yych == 'n') goto yy1149; + if (yych <= 'q') goto yy1141; + goto yy1149; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1141; + if (yych <= 't') goto yy1149; + goto yy1147; + } else { + if (yych <= 'v') goto yy1149; + if (yych == 'x') goto yy1152; + goto yy1141; + } + } + } +yy1144: + ++YYCURSOR; +yy1145: +#line 496 "cpp.re" + { BOOST_WAVE_RET(T_STRINGLIT); } +#line 7968 "cpp_re.inc" +yy1146: + yych = *++YYCURSOR; + goto yy1141; +yy1147: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych <= '9') goto yy1187; + goto yy1139; + } else { + if (yych <= 'F') goto yy1187; + if (yych <= '`') goto yy1139; + if (yych <= 'f') goto yy1187; + goto yy1139; + } +yy1148: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych <= '9') goto yy1180; + goto yy1139; + } else { + if (yych <= 'F') goto yy1180; + if (yych <= '`') goto yy1139; + if (yych <= 'f') goto yy1180; + goto yy1139; + } +yy1149: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy1150: + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1151: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1179; + goto yy1157; +yy1152: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1166; + } + goto yy1139; +yy1153: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '"') { + if (yych <= '\n') { + if (yych == '\t') goto yy1149; + goto yy1139; + } else { + if (yych <= '\f') goto yy1149; + if (yych <= 0x1F) goto yy1139; + if (yych <= '!') goto yy1149; + goto yy1155; + } + } else { + if (yych <= '>') { + if (yych <= '/') goto yy1149; + if (yych >= '8') goto yy1149; + } else { + if (yych <= '?') goto yy1156; + if (yych == '\\') goto yy1157; + goto yy1149; + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1155: + yych = *++YYCURSOR; + goto yy1145; +yy1156: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1158; +yy1157: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1149; + goto yy1139; + } else { + if (yych <= '\'') goto yy1149; + if (yych <= '/') goto yy1139; + goto yy1153; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1151; + goto yy1139; + } else { + if (yych <= 'U') goto yy1148; + if (yych == '\\') goto yy1149; + goto yy1139; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1149; + if (yych <= 'e') goto yy1139; + goto yy1149; + } else { + if (yych == 'n') goto yy1149; + if (yych <= 'q') goto yy1139; + goto yy1149; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1139; + if (yych <= 't') goto yy1149; + goto yy1147; + } else { + if (yych <= 'v') goto yy1149; + if (yych == 'x') goto yy1152; + goto yy1139; + } + } + } +yy1158: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy1158; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy1149; + goto yy1139; + } else { + if (yych <= '\f') goto yy1149; + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } + } else { + if (yych <= '/') { + if (yych <= '"') goto yy1155; + if (yych <= '.') goto yy1149; + } else { + if (yych == '\\') goto yy1157; + goto yy1149; + } + } +yy1160: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 64) { + goto yy1160; + } + if (yych <= '7') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1164; + if (yych <= '/') goto yy1149; + goto yy1153; + } + } + } else { + if (yych <= 'U') { + if (yych == '?') goto yy1165; + if (yych <= 'T') goto yy1149; + goto yy1163; + } else { + if (yych <= 'u') { + if (yych <= 't') goto yy1149; + } else { + if (yych == 'x') goto yy1166; + goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + goto yy1176; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + goto yy1176; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych <= 'f') goto yy1176; + goto yy1149; + } + } + } +yy1163: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + goto yy1169; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + goto yy1169; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych <= 'f') goto yy1169; + goto yy1149; + } + } + } +yy1164: + yyaccept = 1; + YYMARKER = ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1145; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1165: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1168; + goto yy1157; +yy1166: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1166; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy1149; + goto yy1139; + } else { + if (yych <= '\f') goto yy1149; + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } + } else { + if (yych <= '?') { + if (yych <= '"') goto yy1155; + if (yych <= '>') goto yy1149; + goto yy1156; + } else { + if (yych == '\\') goto yy1157; + goto yy1149; + } + } +yy1168: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 32) { + goto yy1158; + } + if (yych <= '!') { + if (yych <= '\n') { + if (yych == '\t') goto yy1149; + goto yy1139; + } else { + if (yych <= '\f') goto yy1149; + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } + } else { + if (yych <= '/') { + if (yych <= '"') goto yy1155; + if (yych <= '.') goto yy1149; + goto yy1160; + } else { + if (yych == '\\') goto yy1157; + goto yy1149; + } + } +yy1169: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1176: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '9') { + if (yych <= '\f') { + if (yych == '\t') goto yy1149; + if (yych <= '\n') goto yy1139; + goto yy1149; + } else { + if (yych <= '!') { + if (yych <= 0x1F) goto yy1139; + goto yy1149; + } else { + if (yych <= '"') goto yy1155; + if (yych <= '/') goto yy1149; + } + } + } else { + if (yych <= 'F') { + if (yych == '?') goto yy1156; + if (yych <= '@') goto yy1149; + } else { + if (yych <= '\\') { + if (yych <= '[') goto yy1149; + goto yy1157; + } else { + if (yych <= '`') goto yy1149; + if (yych >= 'g') goto yy1149; + } + } + } + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1156; + goto yy1157; +yy1179: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 16) { + goto yy1149; + } + if (yych <= '!') goto yy1139; + if (yych <= '"') goto yy1155; + if (yych <= '[') goto yy1158; + goto yy1157; +yy1180: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1181; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1181: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1182; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1182: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1183; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1183: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1184; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1184: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1185; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1185: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1186; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1186: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych <= '9') goto yy1149; + goto yy1139; + } else { + if (yych <= 'F') goto yy1149; + if (yych <= '`') goto yy1139; + if (yych <= 'f') goto yy1149; + goto yy1139; + } +yy1187: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1188; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1188: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych >= ':') goto yy1139; + } else { + if (yych <= 'F') goto yy1189; + if (yych <= '`') goto yy1139; + if (yych >= 'g') goto yy1139; + } +yy1189: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1139; + if (yych <= '9') goto yy1149; + goto yy1139; + } else { + if (yych <= 'F') goto yy1149; + if (yych <= '`') goto yy1139; + if (yych <= 'f') goto yy1149; + goto yy1139; + } +} +#line 500 "cpp.re" + +} + +extrawstringlit: +{ + +#line 8743 "cpp_re.inc" +{ + YYCTYPE yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((YYLIMIT - YYCURSOR) < 12) YYFILL(12); + yych = *YYCURSOR; + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x08) goto yy1192; + if (yych <= '\t') goto yy1193; + goto yy1197; + } else { + if (yych <= '\f') goto yy1193; + if (yych <= '\r') goto yy1199; + } + } else { + if (yych <= '>') { + if (yych == '"') goto yy1200; + goto yy1193; + } else { + if (yych <= '?') goto yy1195; + if (yych == '\\') goto yy1196; + goto yy1193; + } + } +yy1192: + YYCURSOR = YYMARKER; + goto yy1194; +yy1193: + ++YYCURSOR; +yy1194: +#line 507 "cpp.re" + { + goto extrawstringlit; + } +#line 8811 "cpp_re.inc" +yy1195: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '?') goto yy1221; + goto yy1194; +yy1196: + yych = *++YYCURSOR; + if (yych <= '`') { + if (yych <= '7') { + if (yych <= '&') { + if (yych == '"') goto yy1193; + goto yy1192; + } else { + if (yych <= '\'') goto yy1193; + if (yych <= '/') goto yy1192; + goto yy1206; + } + } else { + if (yych <= 'T') { + if (yych == '?') goto yy1204; + goto yy1192; + } else { + if (yych <= 'U') goto yy1203; + if (yych == '\\') goto yy1193; + goto yy1192; + } + } + } else { + if (yych <= 'r') { + if (yych <= 'f') { + if (yych <= 'b') goto yy1193; + if (yych <= 'e') goto yy1192; + goto yy1193; + } else { + if (yych == 'n') goto yy1193; + if (yych <= 'q') goto yy1192; + goto yy1193; + } + } else { + if (yych <= 'u') { + if (yych <= 's') goto yy1192; + if (yych <= 't') goto yy1193; + goto yy1202; + } else { + if (yych <= 'v') goto yy1193; + if (yych == 'x') goto yy1205; + goto yy1192; + } + } + } +yy1197: + ++YYCURSOR; +yy1198: +#line 512 "cpp.re" + { + s->line += count_backslash_newlines(s, cursor) +1; + cursor.column = 1; + goto extrawstringlit; + } +#line 8870 "cpp_re.inc" +yy1199: + yych = *++YYCURSOR; + if (yych == '\n') goto yy1197; + goto yy1198; +yy1200: + ++YYCURSOR; +#line 518 "cpp.re" + { BOOST_WAVE_RET(T_RAWSTRINGLIT); } +#line 8879 "cpp_re.inc" +yy1202: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych <= '9') goto yy1218; + goto yy1192; + } else { + if (yych <= 'F') goto yy1218; + if (yych <= '`') goto yy1192; + if (yych <= 'f') goto yy1218; + goto yy1192; + } +yy1203: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych <= '9') goto yy1211; + goto yy1192; + } else { + if (yych <= 'F') goto yy1211; + if (yych <= '`') goto yy1192; + if (yych <= 'f') goto yy1211; + goto yy1192; + } +yy1204: + yych = *(YYMARKER = ++YYCURSOR); + if (yych == '?') goto yy1210; + goto yy1194; +yy1205: + yych = *++YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1208; + } + goto yy1192; +yy1206: + yych = *++YYCURSOR; + if (yych <= '/') goto yy1194; + if (yych >= '8') goto yy1194; + yych = *++YYCURSOR; + if (yych <= '/') goto yy1194; + if (yych <= '7') goto yy1193; + goto yy1194; +yy1208: + ++YYCURSOR; + if (YYLIMIT <= YYCURSOR) YYFILL(1); + yych = *YYCURSOR; + if (yybm[0+yych] & 128) { + goto yy1208; + } + goto yy1194; +yy1210: + yych = *++YYCURSOR; + if (yych == '/') goto yy1193; + goto yy1192; +yy1211: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1212; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1212: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1213; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1213: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1214; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1214: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1215; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1215: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1216; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1216: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1217; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1217: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych <= '9') goto yy1193; + goto yy1192; + } else { + if (yych <= 'F') goto yy1193; + if (yych <= '`') goto yy1192; + if (yych <= 'f') goto yy1193; + goto yy1192; + } +yy1218: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1219; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1219: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych >= ':') goto yy1192; + } else { + if (yych <= 'F') goto yy1220; + if (yych <= '`') goto yy1192; + if (yych >= 'g') goto yy1192; + } +yy1220: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy1192; + if (yych <= '9') goto yy1193; + goto yy1192; + } else { + if (yych <= 'F') goto yy1193; + if (yych <= '`') goto yy1192; + if (yych <= 'f') goto yy1193; + goto yy1192; + } +yy1221: + ++YYCURSOR; + if ((yych = *YYCURSOR) == '/') goto yy1196; + goto yy1192; +} +#line 519 "cpp.re" + +} diff --git a/extern/shiny/Preprocessor/instantiate_cpp_exprgrammar.cpp b/extern/shiny/Preprocessor/instantiate_cpp_exprgrammar.cpp new file mode 100644 index 000000000..7318c29fa --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_cpp_exprgrammar.cpp @@ -0,0 +1,52 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include +#include + +#include +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the expression_grammar_gen template with the +// correct lexer iterator type. This instantiates the corresponding parse +// function, which in turn instantiates the expression_grammar object (see +// wave/grammars/cpp_expression_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use your own token type the following line must be adjusted +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +template struct boost::wave::grammars::expression_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_cpp_grammar.cpp b/extern/shiny/Preprocessor/instantiate_cpp_grammar.cpp new file mode 100644 index 000000000..89cc3d7f3 --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_cpp_grammar.cpp @@ -0,0 +1,56 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include +#include + +#include +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the cpp_grammar_gen template with the correct +// token type. This instantiates the corresponding pt_parse function, which +// in turn instantiates the cpp_grammar object +// (see wave/grammars/cpp_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use your own token type the following line must be adjusted +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +typedef boost::wave::cpplexer::lex_iterator lexer_type; +typedef std::list > + token_sequence_type; + +template struct boost::wave::grammars::cpp_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_cpp_literalgrs.cpp b/extern/shiny/Preprocessor/instantiate_cpp_literalgrs.cpp new file mode 100644 index 000000000..4fbfb87f2 --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_cpp_literalgrs.cpp @@ -0,0 +1,56 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include +#include +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the intlit_grammar_gen and chlit_grammar_gen +// templates with the correct token type. This instantiates the corresponding +// parse function, which in turn instantiates the corresponding parser object. +// +/////////////////////////////////////////////////////////////////////////////// + +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +template struct boost::wave::grammars::intlit_grammar_gen; +#if BOOST_WAVE_WCHAR_T_SIGNEDNESS == BOOST_WAVE_WCHAR_T_AUTOSELECT || \ + BOOST_WAVE_WCHAR_T_SIGNEDNESS == BOOST_WAVE_WCHAR_T_FORCE_SIGNED +template struct boost::wave::grammars::chlit_grammar_gen; +#endif +template struct boost::wave::grammars::chlit_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_defined_grammar.cpp b/extern/shiny/Preprocessor/instantiate_defined_grammar.cpp new file mode 100644 index 000000000..b7afe3f1e --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_defined_grammar.cpp @@ -0,0 +1,52 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the defined_grammar_gen template +// with the correct token type. This instantiates the corresponding parse +// function, which in turn instantiates the defined_grammar +// object (see wave/grammars/cpp_defined_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use your own token type the following line must be adjusted +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +typedef boost::wave::cpplexer::lex_iterator lexer_type; +template struct boost::wave::grammars::defined_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_predef_macros.cpp b/extern/shiny/Preprocessor/instantiate_predef_macros.cpp new file mode 100644 index 000000000..758ad9734 --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_predef_macros.cpp @@ -0,0 +1,52 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include + +#if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + +#include + +#include +#include + +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// Explicit instantiation of the predefined_macros_grammar_gen template +// with the correct token type. This instantiates the corresponding pt_parse +// function, which in turn instantiates the cpp_predefined_macros_grammar +// object (see wave/grammars/cpp_predef_macros_grammar.hpp) +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use your own token type the following line must be adjusted +typedef boost::wave::cpplexer::lex_token<> token_type; + +// no need to change anything below +typedef boost::wave::cpplexer::lex_iterator lexer_type; +template struct boost::wave::grammars::predefined_macros_grammar_gen; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 + diff --git a/extern/shiny/Preprocessor/instantiate_re2c_lexer.cpp b/extern/shiny/Preprocessor/instantiate_re2c_lexer.cpp new file mode 100644 index 000000000..cd1b8898f --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_re2c_lexer.cpp @@ -0,0 +1,65 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Explicit instantiation of the lex_functor generation function + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include // configuration data + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// This instantiates the correct 'new_lexer' function, which generates the +// C++ lexer used in this sample. You will have to instantiate the +// new_lexer_gen<> template with the same iterator type, as you have used for +// instantiating the boost::wave::context<> object. +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the first +// parameter supplied while instantiating the boost::wave::context<> template +// (see the file cpp.cpp). +// +/////////////////////////////////////////////////////////////////////////////// + +// if you want to use another iterator type for the underlying input stream +// a corresponding explicit template instantiation needs to be added below +template struct boost::wave::cpplexer::new_lexer_gen< + BOOST_WAVE_STRINGTYPE::iterator>; +template struct boost::wave::cpplexer::new_lexer_gen< + BOOST_WAVE_STRINGTYPE::const_iterator>; + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/extern/shiny/Preprocessor/instantiate_re2c_lexer_str.cpp b/extern/shiny/Preprocessor/instantiate_re2c_lexer_str.cpp new file mode 100644 index 000000000..138ed6c3b --- /dev/null +++ b/extern/shiny/Preprocessor/instantiate_re2c_lexer_str.cpp @@ -0,0 +1,64 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + Explicit instantiation of the lex_functor generation function + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include +#include // configuration data + +#if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 + +#include + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// The following file needs to be included only once throughout the whole +// program. +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +// +// If you've used another iterator type as std::string::iterator, you have to +// instantiate the new_lexer_gen<> template for this iterator type too. +// The reason is, that the library internally uses the new_lexer_gen<> +// template with a std::string::iterator. (You just have to undefine the +// following line.) +// +// This is moved into a separate compilation unit to decouple the compilation +// of the C++ lexer from the compilation of the other modules, which helps to +// reduce compilation time. +// +// The template parameter(s) supplied should be identical to the first +// parameter supplied while instantiating the boost::wave::context<> template +// (see the file cpp.cpp). +// +/////////////////////////////////////////////////////////////////////////////// + +#if !defined(BOOST_WAVE_STRINGTYPE_USE_STDSTRING) +template struct boost::wave::cpplexer::new_lexer_gen; +template struct boost::wave::cpplexer::new_lexer_gen; +#endif + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION != 0 diff --git a/extern/shiny/Preprocessor/token_ids.cpp b/extern/shiny/Preprocessor/token_ids.cpp new file mode 100644 index 000000000..35e7725b4 --- /dev/null +++ b/extern/shiny/Preprocessor/token_ids.cpp @@ -0,0 +1,447 @@ +/*============================================================================= + Boost.Wave: A Standard compliant C++ preprocessor library + The definition of a default set of token identifiers and related + functions. + + http://www.boost.org/ + + Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost + Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +#define BOOST_WAVE_SOURCE 1 + +// disable stupid compiler warnings +#include + +#include +#include +#include + +#include +#include + +// this must occur after all of the includes and before any code appears +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_PREFIX +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { +namespace wave { + +/////////////////////////////////////////////////////////////////////////////// +// return a token name +BOOST_WAVE_STRINGTYPE +get_token_name(token_id tokid) +{ +// Table of token names +// +// Please note that the sequence of token names must match the sequence of +// token id's defined in then enum token_id above. +static char const *tok_names[] = { + /* 256 */ "AND", + /* 257 */ "ANDAND", + /* 258 */ "ASSIGN", + /* 259 */ "ANDASSIGN", + /* 260 */ "OR", + /* 261 */ "ORASSIGN", + /* 262 */ "XOR", + /* 263 */ "XORASSIGN", + /* 264 */ "COMMA", + /* 265 */ "COLON", + /* 266 */ "DIVIDE", + /* 267 */ "DIVIDEASSIGN", + /* 268 */ "DOT", + /* 269 */ "DOTSTAR", + /* 270 */ "ELLIPSIS", + /* 271 */ "EQUAL", + /* 272 */ "GREATER", + /* 273 */ "GREATEREQUAL", + /* 274 */ "LEFTBRACE", + /* 275 */ "LESS", + /* 276 */ "LESSEQUAL", + /* 277 */ "LEFTPAREN", + /* 278 */ "LEFTBRACKET", + /* 279 */ "MINUS", + /* 280 */ "MINUSASSIGN", + /* 281 */ "MINUSMINUS", + /* 282 */ "PERCENT", + /* 283 */ "PERCENTASSIGN", + /* 284 */ "NOT", + /* 285 */ "NOTEQUAL", + /* 286 */ "OROR", + /* 287 */ "PLUS", + /* 288 */ "PLUSASSIGN", + /* 289 */ "PLUSPLUS", + /* 290 */ "ARROW", + /* 291 */ "ARROWSTAR", + /* 292 */ "QUESTION_MARK", + /* 293 */ "RIGHTBRACE", + /* 294 */ "RIGHTPAREN", + /* 295 */ "RIGHTBRACKET", + /* 296 */ "COLON_COLON", + /* 297 */ "SEMICOLON", + /* 298 */ "SHIFTLEFT", + /* 299 */ "SHIFTLEFTASSIGN", + /* 300 */ "SHIFTRIGHT", + /* 301 */ "SHIFTRIGHTASSIGN", + /* 302 */ "STAR", + /* 303 */ "COMPL", + /* 304 */ "STARASSIGN", + /* 305 */ "ASM", + /* 306 */ "AUTO", + /* 307 */ "BOOL", + /* 308 */ "FALSE", + /* 309 */ "TRUE", + /* 310 */ "BREAK", + /* 311 */ "CASE", + /* 312 */ "CATCH", + /* 313 */ "CHAR", + /* 314 */ "CLASS", + /* 315 */ "CONST", + /* 316 */ "CONSTCAST", + /* 317 */ "CONTINUE", + /* 318 */ "DEFAULT", + /* 319 */ "DELETE", + /* 320 */ "DO", + /* 321 */ "DOUBLE", + /* 322 */ "DYNAMICCAST", + /* 323 */ "ELSE", + /* 324 */ "ENUM", + /* 325 */ "EXPLICIT", + /* 326 */ "EXPORT", + /* 327 */ "EXTERN", + /* 328 */ "FLOAT", + /* 329 */ "FOR", + /* 330 */ "FRIEND", + /* 331 */ "GOTO", + /* 332 */ "IF", + /* 333 */ "INLINE", + /* 334 */ "INT", + /* 335 */ "LONG", + /* 336 */ "MUTABLE", + /* 337 */ "NAMESPACE", + /* 338 */ "NEW", + /* 339 */ "OPERATOR", + /* 340 */ "PRIVATE", + /* 341 */ "PROTECTED", + /* 342 */ "PUBLIC", + /* 343 */ "REGISTER", + /* 344 */ "REINTERPRETCAST", + /* 345 */ "RETURN", + /* 346 */ "SHORT", + /* 347 */ "SIGNED", + /* 348 */ "SIZEOF", + /* 349 */ "STATIC", + /* 350 */ "STATICCAST", + /* 351 */ "STRUCT", + /* 352 */ "SWITCH", + /* 353 */ "TEMPLATE", + /* 354 */ "THIS", + /* 355 */ "THROW", + /* 356 */ "TRY", + /* 357 */ "TYPEDEF", + /* 358 */ "TYPEID", + /* 359 */ "TYPENAME", + /* 360 */ "UNION", + /* 361 */ "UNSIGNED", + /* 362 */ "USING", + /* 363 */ "VIRTUAL", + /* 364 */ "VOID", + /* 365 */ "VOLATILE", + /* 366 */ "WCHART", + /* 367 */ "WHILE", + /* 368 */ "PP_DEFINE", + /* 369 */ "PP_IF", + /* 370 */ "PP_IFDEF", + /* 371 */ "PP_IFNDEF", + /* 372 */ "PP_ELSE", + /* 373 */ "PP_ELIF", + /* 374 */ "PP_ENDIF", + /* 375 */ "PP_ERROR", + /* 376 */ "PP_LINE", + /* 377 */ "PP_PRAGMA", + /* 378 */ "PP_UNDEF", + /* 379 */ "PP_WARNING", + /* 380 */ "IDENTIFIER", + /* 381 */ "OCTALINT", + /* 382 */ "DECIMALINT", + /* 383 */ "HEXAINT", + /* 384 */ "INTLIT", + /* 385 */ "LONGINTLIT", + /* 386 */ "FLOATLIT", + /* 387 */ "CCOMMENT", + /* 388 */ "CPPCOMMENT", + /* 389 */ "CHARLIT", + /* 390 */ "STRINGLIT", + /* 391 */ "CONTLINE", + /* 392 */ "SPACE", + /* 393 */ "SPACE2", + /* 394 */ "NEWLINE", + /* 395 */ "POUND_POUND", + /* 396 */ "POUND", + /* 397 */ "ANY", + /* 398 */ "PP_INCLUDE", + /* 399 */ "PP_QHEADER", + /* 400 */ "PP_HHEADER", + /* 401 */ "EOF", + /* 402 */ "EOI", + /* 403 */ "PP_NUMBER", + + // MS extensions + /* 404 */ "MSEXT_INT8", + /* 405 */ "MSEXT_INT16", + /* 406 */ "MSEXT_INT32", + /* 407 */ "MSEXT_INT64", + /* 408 */ "MSEXT_BASED", + /* 409 */ "MSEXT_DECLSPEC", + /* 410 */ "MSEXT_CDECL", + /* 411 */ "MSEXT_FASTCALL", + /* 412 */ "MSEXT_STDCALL", + /* 413 */ "MSEXT_TRY", + /* 414 */ "MSEXT_EXCEPT", + /* 415 */ "MSEXT_FINALLY", + /* 416 */ "MSEXT_LEAVE", + /* 417 */ "MSEXT_INLINE", + /* 418 */ "MSEXT_ASM", + /* 419 */ "MSEXT_REGION", + /* 420 */ "MSEXT_ENDREGION", + + /* 421 */ "IMPORT", + + /* 422 */ "ALIGNAS", + /* 423 */ "ALIGNOF", + /* 424 */ "CHAR16_T", + /* 425 */ "CHAR32_T", + /* 426 */ "CONSTEXPR", + /* 427 */ "DECLTYPE", + /* 428 */ "NOEXCEPT", + /* 429 */ "NULLPTR", + /* 430 */ "STATIC_ASSERT", + /* 431 */ "THREADLOCAL", + /* 432 */ "RAWSTRINGLIT", + }; + + // make sure, I have not forgotten any commas (as I did more than once) + BOOST_STATIC_ASSERT( + sizeof(tok_names)/sizeof(tok_names[0]) == T_LAST_TOKEN-T_FIRST_TOKEN + ); + + unsigned int id = BASEID_FROM_TOKEN(tokid)-T_FIRST_TOKEN; + return (id < T_LAST_TOKEN-T_FIRST_TOKEN) ? tok_names[id] : ""; +} + +/////////////////////////////////////////////////////////////////////////////// +// return a token name +char const * +get_token_value(token_id tokid) +{ +// Table of token values +// +// Please note that the sequence of token names must match the sequence of +// token id's defined in then enum token_id above. +static char const *tok_values[] = { + /* 256 */ "&", + /* 257 */ "&&", + /* 258 */ "=", + /* 259 */ "&=", + /* 260 */ "|", + /* 261 */ "|=", + /* 262 */ "^", + /* 263 */ "^=", + /* 264 */ ",", + /* 265 */ ":", + /* 266 */ "/", + /* 267 */ "/=", + /* 268 */ ".", + /* 269 */ ".*", + /* 270 */ "...", + /* 271 */ "==", + /* 272 */ ">", + /* 273 */ ">=", + /* 274 */ "{", + /* 275 */ "<", + /* 276 */ "<=", + /* 277 */ "(", + /* 278 */ "[", + /* 279 */ "-", + /* 280 */ "-=", + /* 281 */ "--", + /* 282 */ "%", + /* 283 */ "%=", + /* 284 */ "!", + /* 285 */ "!=", + /* 286 */ "||", + /* 287 */ "+", + /* 288 */ "+=", + /* 289 */ "++", + /* 290 */ "->", + /* 291 */ "->*", + /* 292 */ "?", + /* 293 */ "}", + /* 294 */ ")", + /* 295 */ "]", + /* 296 */ "::", + /* 297 */ ";", + /* 298 */ "<<", + /* 299 */ "<<=", + /* 300 */ ">>", + /* 301 */ ">>=", + /* 302 */ "*", + /* 303 */ "~", + /* 304 */ "*=", + /* 305 */ "asm", + /* 306 */ "auto", + /* 307 */ "bool", + /* 308 */ "false", + /* 309 */ "true", + /* 310 */ "break", + /* 311 */ "case", + /* 312 */ "catch", + /* 313 */ "char", + /* 314 */ "class", + /* 315 */ "const", + /* 316 */ "const_cast", + /* 317 */ "continue", + /* 318 */ "default", + /* 319 */ "delete", + /* 320 */ "do", + /* 321 */ "double", + /* 322 */ "dynamic_cast", + /* 323 */ "else", + /* 324 */ "enum", + /* 325 */ "explicit", + /* 326 */ "export", + /* 327 */ "extern", + /* 328 */ "float", + /* 329 */ "for", + /* 330 */ "friend", + /* 331 */ "goto", + /* 332 */ "if", + /* 333 */ "inline", + /* 334 */ "int", + /* 335 */ "long", + /* 336 */ "mutable", + /* 337 */ "namespace", + /* 338 */ "new", + /* 339 */ "operator", + /* 340 */ "private", + /* 341 */ "protected", + /* 342 */ "public", + /* 343 */ "register", + /* 344 */ "reinterpret_cast", + /* 345 */ "return", + /* 346 */ "short", + /* 347 */ "signed", + /* 348 */ "sizeof", + /* 349 */ "static", + /* 350 */ "static_cast", + /* 351 */ "struct", + /* 352 */ "switch", + /* 353 */ "template", + /* 354 */ "this", + /* 355 */ "throw", + /* 356 */ "try", + /* 357 */ "typedef", + /* 358 */ "typeid", + /* 359 */ "typename", + /* 360 */ "union", + /* 361 */ "unsigned", + /* 362 */ "using", + /* 363 */ "virtual", + /* 364 */ "void", + /* 365 */ "volatile", + /* 366 */ "wchar_t", + /* 367 */ "while", + /* 368 */ "#define", + /* 369 */ "#if", + /* 370 */ "#ifdef", + /* 371 */ "#ifndef", + /* 372 */ "#else", + /* 373 */ "#elif", + /* 374 */ "#endif", + /* 375 */ "#error", + /* 376 */ "#line", + /* 377 */ "#pragma", + /* 378 */ "#undef", + /* 379 */ "#warning", + /* 380 */ "", // identifier + /* 381 */ "", // octalint + /* 382 */ "", // decimalint + /* 383 */ "", // hexlit + /* 384 */ "", // intlit + /* 385 */ "", // longintlit + /* 386 */ "", // floatlit + /* 387 */ "", // ccomment + /* 388 */ "", // cppcomment + /* 389 */ "", // charlit + /* 390 */ "", // stringlit + /* 391 */ "", // contline + /* 392 */ "", // space + /* 393 */ "", // space2 + /* 394 */ "\n", + /* 395 */ "##", + /* 396 */ "#", + /* 397 */ "", // any + /* 398 */ "#include", + /* 399 */ "#include", + /* 400 */ "#include", + /* 401 */ "", // eof + /* 402 */ "", // eoi + /* 403 */ "", // pp-number + + // MS extensions + /* 404 */ "__int8", + /* 405 */ "__int16", + /* 406 */ "__int32", + /* 407 */ "__int64", + /* 408 */ "__based", + /* 409 */ "__declspec", + /* 410 */ "__cdecl", + /* 411 */ "__fastcall", + /* 412 */ "__stdcall", + /* 413 */ "__try", + /* 414 */ "__except", + /* 415 */ "__finally", + /* 416 */ "__leave", + /* 417 */ "__inline", + /* 418 */ "__asm", + /* 419 */ "#region", + /* 420 */ "#endregion", + + /* 421 */ "import", + + /* 422 */ "alignas", + /* 423 */ "alignof", + /* 424 */ "char16_t", + /* 425 */ "char32_t", + /* 426 */ "constexpr", + /* 427 */ "decltype", + /* 428 */ "noexcept", + /* 429 */ "nullptr", + /* 430 */ "static_assert", + /* 431 */ "threadlocal", + /* 432 */ "", // extrawstringlit + }; + + // make sure, I have not forgotten any commas (as I did more than once) + BOOST_STATIC_ASSERT( + sizeof(tok_values)/sizeof(tok_values[0]) == T_LAST_TOKEN-T_FIRST_TOKEN + ); + + unsigned int id = BASEID_FROM_TOKEN(tokid)-T_FIRST_TOKEN; + return (id < T_LAST_TOKEN-T_FIRST_TOKEN) ? tok_values[id] : ""; +} + +/////////////////////////////////////////////////////////////////////////////// +} // namespace wave +} // namespace boost + +// the suffix header occurs after all of the code +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + + diff --git a/extern/shiny/Readme.txt b/extern/shiny/Readme.txt new file mode 100644 index 000000000..613321990 --- /dev/null +++ b/extern/shiny/Readme.txt @@ -0,0 +1,33 @@ +shiny - a shader and material management library for OGRE + +FEATURES + +- High-level layer on top of OGRE's material system. It allows you to generate multiple techniques for all your materials from a set of high-level per-material properties. + +- Several available Macros in shader source files. Just a few examples of the possibilities: binding OGRE auto constants, binding uniforms to material properties, foreach loops (repeat shader source a given number of times), retrieving per-material properties in an #if condition, automatic packing for vertex to fragment passthroughs. These macros allow you to generate even very complex shaders (for example the Ogre::Terrain shader) without assembling them in C++ code. + +- Integrated preprocessor (no, I didn't reinvent the wheel, I used boost::wave which turned out to be an excellent choice) that allows me to blend out macros that shouldn't be in use because e.g. the shader permutation doesn't need this specific feature. + +- User settings integration. They can be set by a C++ interface and retrieved through a macro in shader files. + +- Automatic handling of shader permutations, i.e. shaders are shared between materials in a smart way. + +- An optional "meta-language" (well, actually it's just a small header with some conditional defines) that you may use to compile the same shader source for different target languages. If you don't like it, you can still code in GLSL / CG etc separately. You can also switch between the languages at runtime. + +- On-demand material and shader creation. It uses Ogre's material listener to compile the shaders as soon as they are needed for rendering, and not earlier. + +- Shader changes are fully dynamic and real-time. Changing a user setting will recompile all shaders affected by this setting when they are next needed. + +- Serialization system that extends Ogre's material script system, it uses Ogre's script parser, but also adds some additional properties that are not available in Ogre's material system. + +- A concept called "Configuration" allowing you to create a different set of your shaders, doing the same thing except for some minor differences: the properties that are overridden by the active configuration. Possible uses for this are using simpler shaders (no shadows, no fog etc) when rendering for example realtime reflections or a minimap. You can easily switch between configurations by changing the active Ogre material scheme (for example on a viewport level). + +- Fixed function support. You can globally enable or disable shaders at any time, and for texture units you can specify if they're only needed for the shader-based path (e.g. normal maps) or if they should also be created in the fixed function path. + +LICENSE + +see License.txt + +AUTHOR + +scrawl From b1ffdf855fbab4df838a86e3f310c876261dc000 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 26 Jan 2013 04:48:53 -0800 Subject: [PATCH 450/916] Reset the initial state of animated nodes on the skeleton instances This is so the animation specifies node keyframe data based on the node's parent. This will also be necessary for applying animations from different skeleton sources, as they can have different binding positions (even native .skeleton resources will need to specify animation data this way). --- apps/openmw/mwrender/animation.cpp | 22 +++++++++++++++++++++- components/nifogre/ogre_nif_loader.cpp | 15 ++++++--------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5a5761faa..a36155dbe 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,7 +78,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); - mStartPosition = mNonAccumRoot->getPosition(); + mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; asiter = aset->getAnimationStateIterator(); @@ -93,6 +93,26 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } + + // Reset initial state of bones that are animated, so the animation correctly applies. + if(skelinst->getNumAnimations() > 0) + { + Ogre::Animation *anim = skelinst->getAnimation(0); + Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); + while(trackiter.hasMoreElements()) + { + const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); + const Ogre::Node *srcbone = dynamic_cast(srcnode); + if(!srcbone || !skelinst->hasBone(srcbone->getName())) + continue; + + Ogre::Bone *bone = skelinst->getBone(srcbone->getName()); + bone->setOrientation(Ogre::Quaternion::IDENTITY); + bone->setPosition(Ogre::Vector3::ZERO); + bone->setScale(Ogre::Vector3(1.0f)); + bone->setInitialState(); + } + } } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index adc05f7e7..ce0fb00fc 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -193,19 +193,16 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? anim->getNodeTrack(bone->getHandle()) : anim->createNodeTrack(bone->getHandle(), bone); - const Ogre::Quaternion &startquat = bone->getInitialOrientation(); - const Ogre::Vector3 &starttrans = bone->getInitialPosition(); - const Ogre::Vector3 &startscale = bone->getInitialScale(); Ogre::Quaternion lastquat, curquat; Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); Ogre::Vector3 lastscale(1.0f), curscale(1.0f); if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = startquat.Inverse() * quatiter->mValue; + lastquat = curquat = quatiter->mValue; if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue - starttrans; + lasttrans = curtrans = traniter->mValue; if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + lastscale = curscale = Ogre::Vector3(scaleiter->mValue); float begTime = std::max(kfc->timeStart, startTime); float endTime = std::min(kfc->timeStop, stopTime); bool didlast = false; @@ -235,19 +232,19 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const { lastquat = curquat; if(++quatiter != quatkeys.mKeys.end()) - curquat = startquat.Inverse() * quatiter->mValue; + curquat = quatiter->mValue; } while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) { lasttrans = curtrans; if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue - starttrans; + curtrans = traniter->mValue; } while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) { lastscale = curscale; if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + curscale = Ogre::Vector3(scaleiter->mValue); } Ogre::TransformKeyFrame *kframe; From 5579df30ff260c48861040350c9c8b7d509d6573 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sat, 26 Jan 2013 18:19:04 +0100 Subject: [PATCH 451/916] Implemented data/data-local support and added settingshandlers to main.cpp --- apps/launcher/main.cpp | 144 +++++++++++++++++++++++- apps/launcher/settings/gamesettings.cpp | 125 +++++++++++++++++++- apps/launcher/settings/gamesettings.hpp | 43 ++++++- 3 files changed, 300 insertions(+), 12 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 7c4cb5f7e..3fef62bc6 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,8 +1,22 @@ #include +#include +#include +#include #include +#include +#include +#include +#include #include +#include + +#include + #include "maindialog.hpp" +#include "settings/gamesettings.hpp" +#include "settings/graphicssettings.hpp" + int main(int argc, char *argv[]) { @@ -30,14 +44,136 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); - MainDialog mainWin; + // Create setting file handlers - if (mainWin.setup()) { + Files::ConfigurationManager cfgMgr; + QString userPath = QString::fromStdString(cfgMgr.getUserPath().string()); + QString globalPath = QString::fromStdString(cfgMgr.getGlobalPath().string()); - mainWin.show(); - return app.exec(); + GameSettings gameSettings(cfgMgr); + GraphicsSettings graphicsSettings; + + QStringList paths; + paths.append(userPath + QString("openmw.cfg")); + paths.append(QString("openmw.cfg")); + paths.append(globalPath + QString("openmw.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error opening OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return 0; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + gameSettings.readFile(stream); + } + file.close(); } + if (gameSettings.getDataDirs().isEmpty()) + { + QMessageBox msgBox; + msgBox.setWindowTitle("Error detecting Morrowind installation"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(QObject::tr("
Could not find the Data Files location

\ + The directory containing the data files was not found.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + QString selectedFile; + if (msgBox.clickedButton() == dirSelectButton) { + selectedFile = QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select master file"), + QDir::currentPath(), + QString("Morrowind master file (*.esm)")); + } + + if (selectedFile.isEmpty()) + return 0; // Cancel was clicked; + + qDebug() << selectedFile; + QFileInfo info(selectedFile); + + // Add the new dir to the settings file and to the data dir container + gameSettings.setValue(QString("data"), info.absolutePath()); + gameSettings.addDataDir(info.absolutePath()); + + } + + // On to the graphics settings + qDebug() << userPath; + + QFile localDefault(QString("settings-default.cfg")); + QFile globalDefault(globalPath + QString("settings-default.cfg")); + + if (!localDefault.exists() && !globalDefault.exists()) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error reading OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not find settings-default.cfg

\ + The problem may be due to an incomplete installation of OpenMW.
\ + Reinstalling OpenMW may resolve the problem.")); + msgBox.exec(); + return 0; + } + + paths.clear(); + paths.append(globalPath + QString("settings-default.cfg")); + paths.append(QString("settings-default.cfg")); + + paths.append(userPath + QString("settings.cfg")); + paths.append(QString("settings.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error opening OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return 0; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + graphicsSettings.readFile(stream); + } + file.close(); + } + + + MainDialog mainWin; + mainWin.setup(); + + mainWin.show(); + QCoreApplication::processEvents(); + return app.exec(); + + return 0; } diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 32f03ddbe..2420c1e6c 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -1,13 +1,17 @@ #include +#include #include #include #include #include +#include + #include "gamesettings.hpp" -GameSettings::GameSettings() +GameSettings::GameSettings(Files::ConfigurationManager &cfg) + : mCfgMgr(cfg) { } @@ -15,11 +19,124 @@ GameSettings::~GameSettings() { } +void GameSettings::validatePaths() +{ + qDebug() << "validate paths!"; + + if (mSettings.isEmpty()) + return; + + QStringList paths = mSettings.values(QString("data")); + Files::PathContainer dataDirs; + + foreach (const QString &path, paths) { + dataDirs.push_back(Files::PathContainer::value_type(path.toStdString())); + } + + // Parse the data dirs to convert the tokenized paths + mCfgMgr.processPaths(dataDirs); + +// // Replace the existing data paths with valid untokenized ones +// mSettings.remove(QString("data")); + mDataDirs.clear(); + + for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { + QString path = QString::fromStdString(it->string()); + path.remove(QChar('\"')); + + QDir dir(path); + if (dir.exists()) + mDataDirs.append(path); + } + + // Do the same for data-local + QString local = mSettings.value(QString("data-local")); + + if (local.isEmpty()) + return; + + dataDirs.clear(); + dataDirs.push_back(Files::PathContainer::value_type(local.toStdString())); + + mCfgMgr.processPaths(dataDirs); +// mSettings.remove(QString("data-local")); + + if (!dataDirs.empty()) { + QString path = QString::fromStdString(dataDirs.front().string()); + path.remove(QChar('\"')); + + QDir dir(path); + if (dir.exists()) + mDataLocal = path; + } + qDebug() << mSettings; + + +} + +QStringList GameSettings::values(const QString &key, const QStringList &defaultValues) +{ + if (!mSettings.values(key).isEmpty()) + return mSettings.values(key); + return defaultValues; +} + +bool GameSettings::readFile(QTextStream &stream) +{ + QMap cache; + QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); + + while (!stream.atEnd()) { + QString line = stream.readLine().simplified(); + + if (line.isEmpty() || line.startsWith("#")) + continue; + + qDebug() << "line: " << line; + if (keyRe.indexIn(line) != -1) { + + QString key = keyRe.cap(1).simplified(); + QString value = keyRe.cap(2).simplified(); + + qDebug() << "key: " << key; + // There can be multiple data keys + if (key == QLatin1String("data")) { + cache.insertMulti(key, value); + } else { + cache.insert(key, value); + } + } + } + + if (mSettings.isEmpty()) { + mSettings = cache; // This is the first time we read a file + validatePaths(); + return true; + } + + // Replace values from previous settings + QMapIterator i(cache); + while (i.hasNext()) { + i.next(); + + // Don't remove existing data entries + if (i.key() == QLatin1String("data")) + continue; + + if (mSettings.contains(i.key())) + mSettings.remove(i.key()); + } + + // Merge the changed keys with those which didn't + mSettings.unite(cache); + validatePaths(); + qDebug() << mSettings; + return true; +} + bool GameSettings::writeFile(QTextStream &stream) { - QMap settings = SettingsBase::getSettings(); - - QMapIterator i(settings); + QMapIterator i(mSettings); while (i.hasNext()) { i.next(); diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index c81c67d97..717ce6e87 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -1,15 +1,50 @@ #ifndef GAMESETTINGS_HPP #define GAMESETTINGS_HPP -#include "settingsbase.hpp" +#include -class GameSettings : public SettingsBase> +#include + +class QTextStream; +class QStringList; +class QString; + +namespace Files { typedef std::vector PathContainer; + struct ConfigurationManager;} + +class GameSettings { public: - GameSettings(); + GameSettings(Files::ConfigurationManager &cfg); ~GameSettings(); - bool writeFile(QTextStream &stream); + inline QString value(const QString &key, const QString &defaultValue = QString()) + { + return mSettings.value(key).isEmpty() ? defaultValue : mSettings.value(key); + } + + + inline void setValue(const QString &key, const QString &value) + { + mSettings.insert(key, value); + } + + inline QStringList getDataDirs() { return mDataDirs; } + inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } + inline QString getDataLocal() {return mDataLocal; } + + QStringList values(const QString &key, const QStringList &defaultValues = QStringList()); + bool readFile(QTextStream &stream); + bool writeFile(QTextStream &stream); + +private: + Files::ConfigurationManager &mCfgMgr; + + void validatePaths(); + QMap mSettings; + + QStringList mDataDirs; + QString mDataLocal; }; #endif // GAMESETTINGS_HPP From 7b71b4eb31c53beaa13fd369d3d831b3508810c4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 27 Jan 2013 03:03:48 -0800 Subject: [PATCH 452/916] Add a missing include --- apps/openmw/mwworld/worldimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5d9250ab6..0888a4522 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -16,6 +16,7 @@ #include "player.hpp" #include "manualref.hpp" #include "cellfunctors.hpp" +#include "containerstore.hpp" using namespace Ogre; From 25edba088754aec279b41e25d4b244722cd3d037 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 27 Jan 2013 16:39:51 +0100 Subject: [PATCH 453/916] Rewriting the config code of the pages to use the new settings classes --- apps/launcher/CMakeLists.txt | 3 - apps/launcher/datafilespage.cpp | 368 +++++++++++------------------ apps/launcher/datafilespage.hpp | 13 +- apps/launcher/graphicspage.cpp | 94 ++++---- apps/launcher/graphicspage.hpp | 14 +- apps/launcher/main.cpp | 16 +- apps/launcher/maindialog.cpp | 116 +++++---- apps/launcher/maindialog.hpp | 9 +- apps/launcher/utils/filedialog.cpp | 57 ----- apps/launcher/utils/filedialog.hpp | 28 --- 10 files changed, 290 insertions(+), 428 deletions(-) delete mode 100644 apps/launcher/utils/filedialog.cpp delete mode 100644 apps/launcher/utils/filedialog.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 2895b6345..044a0a0b7 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -12,7 +12,6 @@ set(LAUNCHER settings/gamesettings.cpp settings/graphicssettings.cpp - utils/filedialog.cpp utils/naturalsort.cpp utils/lineedit.cpp utils/profilescombobox.cpp @@ -36,7 +35,6 @@ set(LAUNCHER_HEADER settings/settingsbase.hpp utils/lineedit.hpp - utils/filedialog.hpp utils/naturalsort.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp @@ -55,7 +53,6 @@ set(LAUNCHER_HEADER_MOC model/esm/esmfile.hpp utils/lineedit.hpp - utils/filedialog.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp ) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 6b0539c1d..e25300394 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -6,8 +6,9 @@ #include "model/datafilesmodel.hpp" #include "model/esm/esmfile.hpp" +#include "settings/gamesettings.hpp" + #include "utils/profilescombobox.hpp" -#include "utils/filedialog.hpp" #include "utils/lineedit.hpp" #include "utils/naturalsort.hpp" #include "utils/textinputdialog.hpp" @@ -46,9 +47,10 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) return index1.row() <= index2.row(); } -DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) - : QWidget(parent) - , mCfgMgr(cfg) +DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, QWidget *parent) + : mCfgMgr(cfg) + , mGameSettings(gameSettings) + , QWidget(parent) { // Models mMastersModel = new DataFilesModel(this); @@ -178,6 +180,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) createActions(); setupConfig(); + setupDataFiles(); } void DataFilesPage::createActions() @@ -340,269 +343,176 @@ void DataFilesPage::readConfig() } -bool DataFilesPage::showDataFilesWarning() +void DataFilesPage::setupDataFiles() { + // Set the encoding to the one found in openmw.cfg or the default + mMastersModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); + mPluginsModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); - QMessageBox msgBox; - msgBox.setWindowTitle("Error detecting Morrowind installation"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("
Could not find the Data Files location

\ - The directory containing the data files was not found.

\ - Press \"Browse...\" to specify the location manually.
")); + QStringList paths = mGameSettings.getDataDirs(); - QAbstractButton *dirSelectButton = - msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); - - msgBox.exec(); - - if (msgBox.clickedButton() == dirSelectButton) { - - // Show a custom dir selection dialog which only accepts valid dirs - QString selectedDir = FileDialog::getExistingDirectory( - this, tr("Select Data Files Directory"), - QDir::currentPath(), - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - - // Add the user selected data directory - if (!selectedDir.isEmpty()) { - mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); - mCfgMgr.processPaths(mDataDirs); - } else { - // Cancel from within the dir selection dialog - return false; - } - - } else { - // Cancel - return false; - } - - return true; -} - -bool DataFilesPage::setupDataFiles() -{ - // We use the Configuration Manager to retrieve the configuration values - boost::program_options::variables_map variables; - boost::program_options::options_description desc; - - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) - ("data-local", boost::program_options::value()->default_value("")) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("encoding", boost::program_options::value()->default_value("win1252")); - - boost::program_options::notify(variables); - - mCfgMgr.readConfiguration(variables, desc); - - if (variables["data"].empty()) { - if (!showDataFilesWarning()) - return false; - } else { - mDataDirs = Files::PathContainer(variables["data"].as()); - } - - std::string local = variables["data-local"].as(); - if (!local.empty()) { - mDataLocal.push_back(Files::PathContainer::value_type(local)); - } - - mCfgMgr.processPaths(mDataDirs); - mCfgMgr.processPaths(mDataLocal); - - // Second chance to display the warning, the data= entries are invalid - while (mDataDirs.empty()) { - if (!showDataFilesWarning()) - return false; - } - - // Set the charset for reading the esm/esp files - QString encoding = QString::fromStdString(variables["encoding"].as()); - if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { - mMastersModel->setEncoding(encoding); - mPluginsModel->setEncoding(encoding); - } - - // Add the paths to the respective models - for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { - QString path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); + foreach (const QString &path, paths) { mMastersModel->addMasters(path); mPluginsModel->addPlugins(path); } - // Same for the data-local paths - for (Files::PathContainer::iterator it = mDataLocal.begin(); it != mDataLocal.end(); ++it) { - QString path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - mMastersModel->addMasters(path); - mPluginsModel->addPlugins(path); + QString dataLocal = mGameSettings.getDataLocal(); + if (!dataLocal.isEmpty()) { + mMastersModel->addMasters(dataLocal); + mPluginsModel->addPlugins(dataLocal); } - mMastersModel->sort(0); - mPluginsModel->sort(0); -// mMastersTable->sortByColumn(3, Qt::AscendingOrder); -// mPluginsTable->sortByColumn(3, Qt::AscendingOrder); - - - readConfig(); - return true; } void DataFilesPage::writeConfig(QString profile) { - // Don't overwrite the config if no masters are found - if (mMastersModel->rowCount() < 1) - return; +// // Don't overwrite the config if no masters are found +// if (mMastersModel->rowCount() < 1) +// return; - QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); - QDir userPath(pathStr); +// QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); +// QDir userPath(pathStr); - if (!userPath.exists()) { - if (!userPath.mkpath(pathStr)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error creating OpenMW configuration directory"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not create %0

\ - Please make sure you have the right permissions and try again.
").arg(pathStr)); - msgBox.exec(); +// if (!userPath.exists()) { +// if (!userPath.mkpath(pathStr)) { +// QMessageBox msgBox; +// msgBox.setWindowTitle("Error creating OpenMW configuration directory"); +// msgBox.setIcon(QMessageBox::Critical); +// msgBox.setStandardButtons(QMessageBox::Ok); +// msgBox.setText(tr("
Could not create %0

\ +// Please make sure you have the right permissions and try again.
").arg(pathStr)); +// msgBox.exec(); - qApp->quit(); - return; - } - } - // Open the OpenMW config as a QFile - QFile file(pathStr.append("openmw.cfg")); +// qApp->quit(); +// return; +// } +// } +// // Open the OpenMW config as a QFile +// QFile file(pathStr.append("openmw.cfg")); - if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { - // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not open or create %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); - msgBox.exec(); +// if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { +// // File cannot be opened or created +// QMessageBox msgBox; +// msgBox.setWindowTitle("Error writing OpenMW configuration file"); +// msgBox.setIcon(QMessageBox::Critical); +// msgBox.setStandardButtons(QMessageBox::Ok); +// msgBox.setText(tr("
Could not open or create %0

\ +// Please make sure you have the right permissions and try again.
").arg(file.fileName())); +// msgBox.exec(); - qApp->quit(); - return; - } +// qApp->quit(); +// return; +// } - QTextStream in(&file); - QByteArray buffer; +// QTextStream in(&file); +// QByteArray buffer; - // Remove all previous entries from config - while (!in.atEnd()) { - QString line = in.readLine(); - if (!line.startsWith("master") && - !line.startsWith("plugin") && - !line.startsWith("data") && - !line.startsWith("data-local")) - { - buffer += line += "\n"; - } - } +// // Remove all previous entries from config +// while (!in.atEnd()) { +// QString line = in.readLine(); +// if (!line.startsWith("master") && +// !line.startsWith("plugin") && +// !line.startsWith("data") && +// !line.startsWith("data-local")) +// { +// buffer += line += "\n"; +// } +// } - file.close(); +// file.close(); - // Now we write back the other config entries - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not write to %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); - msgBox.exec(); +// // Now we write back the other config entries +// if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { +// QMessageBox msgBox; +// msgBox.setWindowTitle("Error writing OpenMW configuration file"); +// msgBox.setIcon(QMessageBox::Critical); +// msgBox.setStandardButtons(QMessageBox::Ok); +// msgBox.setText(tr("
Could not write to %0

\ +// Please make sure you have the right permissions and try again.
").arg(file.fileName())); +// msgBox.exec(); - qApp->quit(); - return; - } +// qApp->quit(); +// return; +// } - if (!buffer.isEmpty()) { - file.write(buffer); - } +// if (!buffer.isEmpty()) { +// file.write(buffer); +// } - QTextStream gameConfig(&file); - - // First write the list of data dirs - mCfgMgr.processPaths(mDataDirs); - mCfgMgr.processPaths(mDataLocal); - - QString path; - - // data= directories - for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { - path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - - // Make sure the string is quoted when it contains spaces - if (path.contains(" ")) { - gameConfig << "data=\"" << path << "\"" << endl; - } else { - gameConfig << "data=" << path << endl; - } - } - - // data-local directory - if (!mDataLocal.empty()) { - path = QString::fromStdString(mDataLocal.front().string()); - path.remove(QChar('\"')); - - if (path.contains(" ")) { - gameConfig << "data-local=\"" << path << "\"" << endl; - } else { - gameConfig << "data-local=" << path << endl; - } - } +// QTextStream gameConfig(&file); - if (profile.isEmpty()) - profile = mProfilesComboBox->currentText(); +// QString path; - if (profile.isEmpty()) - return; +// // data= directories +// for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { +// path = QString::fromStdString(it->string()); +// path.remove(QChar('\"')); - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } +// // Make sure the string is quoted when it contains spaces +// if (path.contains(" ")) { +// gameConfig << "data=\"" << path << "\"" << endl; +// } else { +// gameConfig << "data=" << path << endl; +// } +// } - mLauncherConfig->beginGroup("Profiles"); - mLauncherConfig->setValue("CurrentProfile", profile); +// // data-local directory +// if (!mDataLocal.empty()) { +// path = QString::fromStdString(mDataLocal.front().string()); +// path.remove(QChar('\"')); - // Open the profile-name subgroup - mLauncherConfig->beginGroup(profile); - mLauncherConfig->remove(""); // Clear the subgroup +// if (path.contains(" ")) { +// gameConfig << "data-local=\"" << path << "\"" << endl; +// } else { +// gameConfig << "data-local=" << path << endl; +// } +// } - // Now write the masters to the configs - const QStringList masters = mMastersModel->checkedItems(); - // We don't use foreach because we need i - for (int i = 0; i < masters.size(); ++i) { - const QString currentMaster = masters.at(i); +// if (profile.isEmpty()) +// profile = mProfilesComboBox->currentText(); - mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster); - gameConfig << "master=" << currentMaster << endl; +// if (profile.isEmpty()) +// return; - } +// // Make sure we have no groups open +// while (!mLauncherConfig->group().isEmpty()) { +// mLauncherConfig->endGroup(); +// } - // And finally write all checked plugins - const QStringList plugins = mPluginsModel->checkedItems(); +// mLauncherConfig->beginGroup("Profiles"); +// mLauncherConfig->setValue("CurrentProfile", profile); - for (int i = 0; i < plugins.size(); ++i) { - const QString currentPlugin = plugins.at(i); - mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin); - gameConfig << "plugin=" << currentPlugin << endl; - } +// // Open the profile-name subgroup +// mLauncherConfig->beginGroup(profile); +// mLauncherConfig->remove(""); // Clear the subgroup - file.close(); - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - mLauncherConfig->sync(); +// // Now write the masters to the configs +// const QStringList masters = mMastersModel->checkedItems(); + +// // We don't use foreach because we need i +// for (int i = 0; i < masters.size(); ++i) { +// const QString currentMaster = masters.at(i); + +// mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster); +// gameConfig << "master=" << currentMaster << endl; + +// } + +// // And finally write all checked plugins +// const QStringList plugins = mPluginsModel->checkedItems(); + +// for (int i = 0; i < plugins.size(); ++i) { +// const QString currentPlugin = plugins.at(i); +// mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin); +// gameConfig << "plugin=" << currentPlugin << endl; +// } + +// file.close(); +// mLauncherConfig->endGroup(); +// mLauncherConfig->endGroup(); +// mLauncherConfig->sync(); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 13668ec30..e40d29d60 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -3,9 +3,6 @@ #include #include -#include "utils/profilescombobox.hpp" -#include - class QTableView; class QSortFilterProxyModel; @@ -17,6 +14,8 @@ class ProfilesComboBox; class DataFilesModel; class TextInputDialog; +class ProfilesComboBox; +class GameSettings; namespace Files { struct ConfigurationManager; } @@ -25,13 +24,11 @@ class DataFilesPage : public QWidget Q_OBJECT public: - DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); + DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, QWidget *parent = 0); ProfilesComboBox *mProfilesComboBox; void writeConfig(QString profile = QString()); - bool showDataFilesWarning(); - bool setupDataFiles(); public slots: void setCheckState(QModelIndex index); @@ -76,10 +73,9 @@ private: QAction *mUncheckAction; Files::ConfigurationManager &mCfgMgr; - Files::PathContainer mDataDirs; - Files::PathContainer mDataLocal; QSettings *mLauncherConfig; + GameSettings &mGameSettings; TextInputDialog *mNewProfileDialog; @@ -87,6 +83,7 @@ private: // const QStringList selectedMasters(); void createActions(); + void setupDataFiles(); void setupConfig(); void readConfig(); diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2c4f3430c..fa9d5d254 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -3,12 +3,12 @@ #include #include -#include #include #include -#include +//#include +#include "settings/graphicssettings.hpp" #include "utils/naturalsort.hpp" #include "graphicspage.hpp" @@ -25,9 +25,10 @@ QString getAspect(int x, int y) return QString(QString::number(xaspect) + ":" + QString::number(yaspect)); } -GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent) - : QWidget(parent) - , mCfgMgr(cfg) +GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent) + : mCfgMgr(cfg) + , mGraphicsSettings(graphicsSetting) + , QWidget(parent) { QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this); @@ -117,9 +118,8 @@ bool GraphicsPage::setupOgre() #endif } - boost::filesystem::path absPluginPath = boost::filesystem::absolute(boost::filesystem::path(pluginDir)); - - pluginDir = absPluginPath.string(); + QDir dir(QString::fromStdString(pluginDir)); + pluginDir = dir.absolutePath().toStdString(); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mOgre); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mOgre); @@ -154,20 +154,16 @@ bool GraphicsPage::setupOgre() msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not select a valid render system

\ - Please make sure the plugins.cfg file exists and contains a valid rendering plugin.
")); + Please make sure the plugins.cfg file exists and contains a valid rendering plugin.
")); msgBox.exec(); - return false; } // Now fill the GUI elements - int index = mRendererComboBox->findText(QString::fromStdString(Settings::Manager::getString("render system", "Video"))); - + int index = mRendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system"))); if ( index != -1) { mRendererComboBox->setCurrentIndex(index); - } - else - { + } else { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(direct3DName)); #else @@ -180,45 +176,49 @@ bool GraphicsPage::setupOgre() mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); - readConfig(); + // Load the rest of the values + loadSettings(); return true; } -void GraphicsPage::readConfig() +void GraphicsPage::loadSettings() { - if (Settings::Manager::getBool("vsync", "Video")) - mVSyncCheckBox->setCheckState(Qt::Checked); + if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) + mVSyncCheckBox->setCheckState(Qt::Checked); - if (Settings::Manager::getBool("fullscreen", "Video")) - mFullScreenCheckBox->setCheckState(Qt::Checked); + if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) + mFullScreenCheckBox->setCheckState(Qt::Checked); - int aaIndex = mAntiAliasingComboBox->findText(QString::fromStdString(Settings::Manager::getString("antialiasing", "Video"))); - if (aaIndex != -1) - mAntiAliasingComboBox->setCurrentIndex(aaIndex); + int aaIndex = mAntiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); + if (aaIndex != -1) + mAntiAliasingComboBox->setCurrentIndex(aaIndex); - QString resolution = QString::number(Settings::Manager::getInt("resolution x", "Video")); - resolution.append(" x " + QString::number(Settings::Manager::getInt("resolution y", "Video"))); + QString resolution = mGraphicsSettings.value(QString("Video/resolution x")); + resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); - int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); - if (resIndex != -1) - mResolutionComboBox->setCurrentIndex(resIndex); + int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); + qDebug() << "resolution from file: " << resolution; + if (resIndex != -1) + mResolutionComboBox->setCurrentIndex(resIndex); } -void GraphicsPage::writeConfig() +void GraphicsPage::saveSettings() { - Settings::Manager::setBool("vsync", "Video", mVSyncCheckBox->checkState()); - Settings::Manager::setBool("fullscreen", "Video", mFullScreenCheckBox->checkState()); - Settings::Manager::setString("antialiasing", "Video", mAntiAliasingComboBox->currentText().toStdString()); - Settings::Manager::setString("render system", "Video", mRendererComboBox->currentText().toStdString()); + mVSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true")) + : mGraphicsSettings.setValue(QString("Video/vsync"), QString("false")); - // Get the current resolution, but with the tabs replaced with a single space - QString resolution = mResolutionComboBox->currentText().simplified(); - QStringList tokens = resolution.split(" ", QString::SkipEmptyParts); + mFullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) + : mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false")); - int resX = tokens.at(0).toInt(); - int resY = tokens.at(2).toInt(); - Settings::Manager::setInt("resolution x", "Video", resX); - Settings::Manager::setInt("resolution y", "Video", resY); + mGraphicsSettings.setValue(QString("Video/antialiasing"), mAntiAliasingComboBox->currentText()); + mGraphicsSettings.setValue(QString("Video/render system"), mRendererComboBox->currentText()); + + QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); + + if (resolutionRe.exactMatch(mResolutionComboBox->currentText().simplified())) { + mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); + mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + } } QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer) @@ -232,16 +232,14 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy { 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) - { + 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::fromStdString((*opt_it).c_str()).simplified(); } } - } // Sort ascending @@ -258,7 +256,7 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) { - QString key ("Video Mode"); + QString key("Video Mode"); QStringList result; uint row = 0; diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index b8166f672..48b9ff785 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -5,8 +5,8 @@ #include #include -#include -#include +//#include +//#include // Static plugin headers #ifdef ENABLE_PLUGIN_GL @@ -21,6 +21,8 @@ class QCheckBox; class QStackedWidget; class QSettings; +class GraphicsSettings; + namespace Files { struct ConfigurationManager; } class GraphicsPage : public QWidget @@ -28,10 +30,10 @@ class GraphicsPage : public QWidget Q_OBJECT public: - GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent = 0); + GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0); + void saveSettings(); bool setupOgre(); - void writeConfig(); public slots: void rendererChanged(const QString &renderer); @@ -58,12 +60,14 @@ private: QCheckBox *mFullScreenCheckBox; Files::ConfigurationManager &mCfgMgr; + GraphicsSettings &mGraphicsSettings; QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); QStringList getAvailableResolutions(Ogre::RenderSystem *renderer); void createPages(); - void readConfig(); + void loadSettings(); + }; #endif diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 3fef62bc6..43bf50fbc 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -138,9 +138,7 @@ int main(int argc, char *argv[]) paths.clear(); paths.append(globalPath + QString("settings-default.cfg")); paths.append(QString("settings-default.cfg")); - paths.append(userPath + QString("settings.cfg")); - paths.append(QString("settings.cfg")); foreach (const QString &path, paths) { qDebug() << "Loading: " << path; @@ -166,14 +164,14 @@ int main(int argc, char *argv[]) } - MainDialog mainWin; - mainWin.setup(); + MainDialog mainWin(gameSettings, graphicsSettings); + + if (mainWin.setup()) { + mainWin.show(); + } else { + return 0; + } - mainWin.show(); - QCoreApplication::processEvents(); return app.exec(); - - - return 0; } diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 674ccdf67..4d3d24bd9 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,11 +1,20 @@ #include +#include "settings/gamesettings.hpp" +#include "settings/graphicssettings.hpp" + +#include "utils/profilescombobox.hpp" + #include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" #include "datafilespage.hpp" -MainDialog::MainDialog() +MainDialog::MainDialog(GameSettings &gameSettings, + GraphicsSettings &graphicsSettings) + : mGameSettings(gameSettings) + , mGraphicsSettings(graphicsSettings) + { QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); @@ -122,8 +131,8 @@ void MainDialog::createIcons() void MainDialog::createPages() { mPlayPage = new PlayPage(this); - mGraphicsPage = new GraphicsPage(mCfgMgr, this); - mDataFilesPage = new DataFilesPage(mCfgMgr, this); + mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this); + mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); @@ -152,46 +161,17 @@ void MainDialog::createPages() bool MainDialog::setup() { - // Create the settings manager and load default settings file - const std::string localdefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); - const std::string globaldefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); - - // prefer local - if (boost::filesystem::exists(localdefault)) { - mSettings.loadDefault(localdefault); - } else if (boost::filesystem::exists(globaldefault)) { - mSettings.loadDefault(globaldefault); - } else { - QMessageBox msgBox; - msgBox.setWindowTitle("Error reading OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not find %0

\ - The problem may be due to an incomplete installation of OpenMW.
\ - Reinstalling OpenMW may resolve the problem.").arg(QString::fromStdString(globaldefault))); - msgBox.exec(); - return false; - } - - // load user settings if they exist, otherwise just load the default settings as user settings - const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); - - if (boost::filesystem::exists(settingspath)) - mSettings.loadUser(settingspath); - else if (boost::filesystem::exists(localdefault)) - mSettings.loadUser(localdefault); - else if (boost::filesystem::exists(globaldefault)) - mSettings.loadUser(globaldefault); - // Setup the Graphics page if (!mGraphicsPage->setupOgre()) { return false; } // Setup the Data Files page + /* if (!mDataFilesPage->setupDataFiles()) { return false; - } + }*/ + return true; } @@ -208,11 +188,67 @@ void MainDialog::closeEvent(QCloseEvent *event) { // Now write all config files mDataFilesPage->writeConfig(); - mGraphicsPage->writeConfig(); + mGraphicsPage->saveSettings(); - // Save user settings - const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); - mSettings.saveUser(settingspath); + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + QDir dir(userPath); + + if (!dir.exists()) { + if (!dir.mkpath(userPath)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error creating OpenMW configuration directory"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not create %0

\ + Please make sure you have the right permissions \ + and try again.
").arg(userPath)); + msgBox.exec(); + event->accept(); + } + } + + // Game settings + QFile file(userPath + QString("openmw.cfg")); + + if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0 for writing

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + event->accept(); + } + + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mGameSettings.writeFile(stream); + file.close(); + + // Graphics settings + file.setFileName(userPath + QString("settings.cfg")); + + if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0 for writing

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + event->accept(); + } + + stream.setDevice(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mGraphicsSettings.writeFile(stream); event->accept(); } @@ -221,7 +257,7 @@ void MainDialog::play() { // First do a write of all the configs, just to be sure mDataFilesPage->writeConfig(); - mGraphicsPage->writeConfig(); + //mGraphicsPage->writeConfig(); // Save user settings const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index bf98011cc..c9654b874 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -17,12 +17,15 @@ class PlayPage; class GraphicsPage; class DataFilesPage; +class GameSettings; +class GraphicsSettings; + class MainDialog : public QMainWindow { Q_OBJECT public: - MainDialog(); + MainDialog(GameSettings &gameSettings, GraphicsSettings &GraphicsSettings); public slots: void changePage(QListWidgetItem *current, QListWidgetItem *previous); @@ -43,6 +46,10 @@ private: Files::ConfigurationManager mCfgMgr; Settings::Manager mSettings; + + GameSettings &mGameSettings; + GraphicsSettings &mGraphicsSettings; + }; #endif diff --git a/apps/launcher/utils/filedialog.cpp b/apps/launcher/utils/filedialog.cpp deleted file mode 100644 index 16d677533..000000000 --- a/apps/launcher/utils/filedialog.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "filedialog.hpp" -#include -#include - -FileDialog::FileDialog(QWidget *parent) - : QFileDialog(parent) -{ - // Remove the default Choose button to prevent it being updated elsewhere - QDialogButtonBox *box = qFindChild(this); - Q_ASSERT(box); - box->removeButton(box->button(QDialogButtonBox::Open)); - - // Add our own button so we can disable/enable it - mChooseButton = new QPushButton(tr("&Choose")); - mChooseButton->setIcon(QIcon::fromTheme("document-open")); - mChooseButton->setEnabled(false); - box->addButton(mChooseButton, QDialogButtonBox::AcceptRole); - - connect(this, SIGNAL(directoryEntered(const QString&)), this, SLOT(updateChooseButton(const QString&))); - emit directoryEntered(QDir::currentPath()); -} - -QString FileDialog::getExistingDirectory(QWidget *parent, - const QString &caption, - const QString &dir, - Options options) -{ - // create a non-native file dialog - FileDialog dialog; - dialog.setFileMode(DirectoryOnly); - dialog.setOptions(options |= QFileDialog::DontUseNativeDialog | QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly); - - if (!caption.isEmpty()) - dialog.setWindowTitle(caption); - - if (!dir.isEmpty()) - dialog.setDirectory(dir); - - if (dialog.exec() == QDialog::Accepted) { - return dialog.selectedFiles().value(0); - } - return QString(); -} - -void FileDialog::updateChooseButton(const QString &directory) -{ - QDir currentDir = QDir(directory); - currentDir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); - currentDir.setNameFilters(QStringList() << "*.esm" << "*.esp"); - - if (!currentDir.entryList().isEmpty()) { - // There are data files in the current dir - mChooseButton->setEnabled(true); - } else { - mChooseButton->setEnabled(false); - } -} diff --git a/apps/launcher/utils/filedialog.hpp b/apps/launcher/utils/filedialog.hpp deleted file mode 100644 index 7a161ecb9..000000000 --- a/apps/launcher/utils/filedialog.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef FILEDIALOG_HPP -#define FILEDIALOG_HPP - -#include - -class QPushButton; - -class FileDialog : public QFileDialog -{ - Q_OBJECT - -public: - FileDialog(QWidget *parent = 0); - - static QString getExistingDirectory(QWidget *parent = 0, - const QString &caption = QString(), - const QString &dir = QString(), - Options options = ShowDirsOnly); - -private slots: - void updateChooseButton(const QString &directory); - -private: - QPushButton *mChooseButton; -}; - - -#endif // FILEDIALOG_HPP From e1d39331454e5839e4248941f7b4037e0755b69e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 01:27:12 -0800 Subject: [PATCH 454/916] Remove an unused struct --- components/nifogre/ogre_nif_loader.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index ce0fb00fc..e5e949d0e 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -355,15 +355,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc } -/* Comparitor to help sort Key<> vectors */ -template -struct KeyTimeSort -{ - bool operator()(const Nif::KeyT &lhs, const Nif::KeyT &rhs) const - { return lhs.mTime < rhs.mTime; } -}; - - typedef std::map LoaderMap; static LoaderMap sLoaders; From 7df4d0d19fdb081fb6e813c7c327ad38695a8da1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 21:41:51 -0800 Subject: [PATCH 455/916] Remove an unnecessary cast --- apps/openmw/mwrender/animation.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a36155dbe..c4439841f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -102,11 +102,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(trackiter.hasMoreElements()) { const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); - const Ogre::Node *srcbone = dynamic_cast(srcnode); - if(!srcbone || !skelinst->hasBone(srcbone->getName())) + if(!skelinst->hasBone(srcnode->getName())) continue; - Ogre::Bone *bone = skelinst->getBone(srcbone->getName()); + Ogre::Bone *bone = skelinst->getBone(srcnode->getName()); bone->setOrientation(Ogre::Quaternion::IDENTITY); bone->setPosition(Ogre::Vector3::ZERO); bone->setScale(Ogre::Vector3(1.0f)); From 487c83e94305efb7becf4682feb9c80e9998f99d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 22:09:41 -0800 Subject: [PATCH 456/916] Rename nonaccum to animroot --- components/nifogre/ogre_nif_loader.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e5e949d0e..8dbfbff5a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -305,7 +305,7 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) } -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonaccum, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { if(node->recType == Nif::RC_NiTriShape) return; @@ -326,18 +326,18 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc while(!ctrl.empty()) { if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); + ctrls.push_back(static_cast(ctrl.getPtr())); ctrl = ctrl->next; } Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiTextKeyExtraData && !nonaccum) + if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) { const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); - nonaccum = bone; + animroot = bone; } e = e->extra; } @@ -349,7 +349,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&nonacc for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), nonaccum, textkeys, ctrls, bone); + buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); } } } @@ -369,10 +369,10 @@ void loadResource(Ogre::Resource *resource) const Nif::Node *node = dynamic_cast(nif.getRecord(0)); std::vector ctrls; - Ogre::Bone *nonaccum = NULL; + Ogre::Bone *animroot = NULL; TextKeyMap textkeys; try { - buildBones(skel, node, nonaccum, textkeys, ctrls); + buildBones(skel, node, animroot, textkeys, ctrls); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() <getName()+", but no text keys. Uses NiBSAnimationNode?"); return; } - Ogre::UserObjectBindings &bindings = nonaccum->getUserObjectBindings(); + Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); std::string currentgroup; From 8d98f3649c356dd0e88fba1397d0ccb5cca47f22 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 28 Jan 2013 23:39:11 -0800 Subject: [PATCH 457/916] Use a separate class to handle activator mechanics --- apps/openmw/CMakeLists.txt | 5 +- apps/openmw/mwbase/mechanicsmanager.hpp | 14 ++--- apps/openmw/mwclass/activator.cpp | 2 +- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/activators.cpp | 62 +++++++++++++++++++ apps/openmw/mwmechanics/activators.hpp | 42 +++++++++++++ apps/openmw/mwmechanics/actors.cpp | 14 +---- .../mwmechanics/mechanicsmanagerimp.cpp | 45 +++++++++----- .../mwmechanics/mechanicsmanagerimp.hpp | 19 +++--- apps/openmw/mwworld/scene.cpp | 8 +-- apps/openmw/mwworld/worldimp.cpp | 9 ++- 12 files changed, 168 insertions(+), 56 deletions(-) create mode 100644 apps/openmw/mwmechanics/activators.cpp create mode 100644 apps/openmw/mwmechanics/activators.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ec7700bee..73baa4e72 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -62,8 +62,9 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat character creaturestats magiceffects movement actors drawstate spells - activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate + mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators + drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow + aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index f7bbd6a9f..ec616fcaf 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -37,21 +37,21 @@ namespace MWBase virtual ~MechanicsManager() {} - virtual void addActor (const MWWorld::Ptr& ptr) = 0; - ///< Register an actor for stats management + virtual void add (const MWWorld::Ptr& ptr) = 0; + ///< Register an object for management - virtual void removeActor (const MWWorld::Ptr& ptr) = 0; - ///< Deregister an actor for stats management + virtual void remove (const MWWorld::Ptr& ptr) = 0; + ///< Deregister an object for management - virtual void dropActors (const MWWorld::CellStore *cellStore) = 0; - ///< Deregister all actors in the given cell. + virtual void drop (const MWWorld::CellStore *cellStore) = 0; + ///< Deregister all objects in the given cell. virtual void watchActor (const MWWorld::Ptr& ptr) = 0; ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. virtual void update (float duration, bool paused) = 0; - ///< Update actor stats and store desired velocity vectors in \a movement + ///< Update objects /// /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 292627286..3a60d9c39 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -32,7 +32,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addObject(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor(ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Activator::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 7b0f9f728..90dc70715 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -97,7 +97,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addActor(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor (ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Creature::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cfbc64b87..6069e3b7c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -142,7 +142,7 @@ namespace MWClass void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { physics.addActor(ptr); - MWBase::Environment::get().getMechanicsManager()->addActor(ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Npc::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp new file mode 100644 index 000000000..799d7ecd5 --- /dev/null +++ b/apps/openmw/mwmechanics/activators.cpp @@ -0,0 +1,62 @@ +#include "activators.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +Activators::Activators() +{ +} + +void Activators::addActivator (const MWWorld::Ptr& ptr) +{ + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); + mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); +} + +void Activators::removeActivator (const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + mActivators.erase(iter); +} + +void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) +{ + PtrControllerMap::iterator iter = mActivators.begin(); + while(iter != mActivators.end()) + { + if(iter->first.getCell()==cellStore) + mActivators.erase(iter++); + else + ++iter; + } +} + +void Activators::update(float duration, bool paused) +{ + if(!paused) + { + for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) + iter->second.update(duration); + } +} + +void Activators::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + iter->second.playGroup(groupName, mode, number); +} +void Activators::skipAnimation(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + iter->second.skipAnim(); +} + +} diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp new file mode 100644 index 000000000..3ddb0f843 --- /dev/null +++ b/apps/openmw/mwmechanics/activators.hpp @@ -0,0 +1,42 @@ +#ifndef GAME_MWMECHANICS_ACTIVATORS_H +#define GAME_MWMECHANICS_ACTOVATRS_H + +#include +#include + +#include "character.hpp" + +namespace MWWorld +{ + class Ptr; + class CellStore; +} + +namespace MWMechanics +{ + class Activators + { + typedef std::map PtrControllerMap; + PtrControllerMap mActivators; + + public: + Activators(); + + void addActivator (const MWWorld::Ptr& ptr); + ///< Register an activator + + void removeActivator (const MWWorld::Ptr& ptr); + ///< Deregister an activator + + void dropActivators (const MWWorld::CellStore *cellStore); + ///< Deregister all activators in the given cell. + + void update (float duration, bool paused); + ///< Update activator animations + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6c69c457b..98ae3e755 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -166,9 +166,7 @@ namespace MWMechanics void Actors::addActor (const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - /* Kind of a hack. Activators need a character controller to manage an idle state. */ - if(ptr.getTypeName() == typeid(ESM::Activator).name() || - !MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) + if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); else mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); @@ -205,11 +203,6 @@ namespace MWMechanics PtrControllerMap::iterator iter(mActors.begin()); while(iter != mActors.end()) { - if(iter->first.getTypeName() == typeid(ESM::Activator).name()) - { - iter++; - continue; - } if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { if(iter->second.getState() == CharState_Dead) @@ -304,10 +297,7 @@ namespace MWMechanics void Actors::restoreDynamicStats() { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - { - if(iter->first.getTypeName() != typeid(ESM::Activator).name()) - calculateRestoration(iter->first, 3600); - } + calculateRestoration(iter->first, 3600); } int Actors::countDeaths (const std::string& id) const diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 84145eb08..3e56cbcb1 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -175,33 +175,37 @@ namespace MWMechanics buildPlayer(); } - void MechanicsManager::addActor (const MWWorld::Ptr& ptr) + void MechanicsManager::add(const MWWorld::Ptr& ptr) { - mActors.addActor (ptr); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.addActivator(ptr); + else + mActors.addActor(ptr); } - void MechanicsManager::removeActor (const MWWorld::Ptr& ptr) + void MechanicsManager::remove(const MWWorld::Ptr& ptr) { - if (ptr==mWatched) + if(ptr == mWatched) + mWatched = MWWorld::Ptr(); + mActors.removeActor(ptr); + } + + void MechanicsManager::drop(const MWWorld::CellStore *cellStore) + { + if(!mWatched.isEmpty() && mWatched.getCell() == cellStore) mWatched = MWWorld::Ptr(); - mActors.removeActor (ptr); + mActors.dropActors(cellStore); + mActivators.dropActivators(cellStore); } - void MechanicsManager::dropActors (const MWWorld::Ptr::CellStore *cellStore) - { - if (!mWatched.isEmpty() && mWatched.getCell()==cellStore) - mWatched = MWWorld::Ptr(); - mActors.dropActors (cellStore); - } - - void MechanicsManager::watchActor (const MWWorld::Ptr& ptr) + void MechanicsManager::watchActor(const MWWorld::Ptr& ptr) { mWatched = ptr; } - void MechanicsManager::update (float duration, bool paused) + void MechanicsManager::update(float duration, bool paused) { if (!mWatched.isEmpty()) { @@ -297,7 +301,8 @@ namespace MWMechanics winMgr->configureSkills (majorSkills, minorSkills); } - mActors.update (duration, paused); + mActors.update(duration, paused); + mActivators.update(duration, paused); } void MechanicsManager::restoreDynamicStats() @@ -631,11 +636,17 @@ namespace MWMechanics void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - mActors.playAnimationGroup(ptr, groupName, mode, number); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.playAnimationGroup(ptr, groupName, mode, number); + else + mActors.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { - mActors.skipAnimation(ptr); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.skipAnimation(ptr); + else + mActors.skipAnimation(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index c2bbd96cf..f70242bb9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,6 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include "activators.hpp" #include "actors.hpp" namespace Ogre @@ -29,6 +30,8 @@ namespace MWMechanics bool mUpdatePlayer; bool mClassSelected; bool mRaceSelected; + + Activators mActivators; Actors mActors; void buildPlayer(); @@ -39,21 +42,21 @@ namespace MWMechanics MechanicsManager(); - virtual void addActor (const MWWorld::Ptr& ptr); - ///< Register an actor for stats management + virtual void add (const MWWorld::Ptr& ptr); + ///< Register an object for management - virtual void removeActor (const MWWorld::Ptr& ptr); - ///< Deregister an actor for stats management + virtual void remove (const MWWorld::Ptr& ptr); + ///< Deregister an object for management - virtual void dropActors (const MWWorld::CellStore *cellStore); - ///< Deregister all actors in the given cell. + virtual void drop(const MWWorld::CellStore *cellStore); + ///< Deregister all objects in the given cell. - virtual void watchActor (const MWWorld::Ptr& ptr); + virtual void watchActor(const MWWorld::Ptr& ptr); ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. virtual void update (float duration, bool paused); - ///< Update actor stats and store desired velocity vectors in \a movement + ///< Update objects /// /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index e116dca57..47751acb3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -100,7 +100,7 @@ namespace MWWorld //mPhysics->removeObject("Unnamed_43"); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); - MWBase::Environment::get().getMechanicsManager()->dropActors (*iter); + MWBase::Environment::get().getMechanicsManager()->drop (*iter); MWBase::Environment::get().getSoundManager()->stopSound (*iter); mActiveCells.erase(*iter); } @@ -166,7 +166,7 @@ namespace MWWorld MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->addActor(player); + mechMgr->add(player); mechMgr->watchActor(player); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); @@ -179,7 +179,7 @@ namespace MWWorld mRendering.preCellChange(mCurrentCell); // remove active - MWBase::Environment::get().getMechanicsManager()->removeActor (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); CellStoreCollection::iterator active = mActiveCells.begin(); @@ -443,7 +443,7 @@ namespace MWWorld void Scene::removeObjectFromScene (const Ptr& ptr) { - MWBase::Environment::get().getMechanicsManager()->removeActor (ptr); + MWBase::Environment::get().getMechanicsManager()->remove (ptr); MWBase::Environment::get().getSoundManager()->stopSound3D (ptr); mPhysics->removeObject (ptr.getRefData().getHandle()); mRendering.removeObject (ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0888a4522..a1d713a8a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -700,6 +700,7 @@ namespace MWWorld if (*currCell != newCell) { if (isPlayer) + { if (!newCell.isExterior()) changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos); else @@ -708,7 +709,9 @@ namespace MWWorld int cellY = newCell.mCell->getGridY(); mWorldScene->changeCell(cellX, cellY, pos, false); } - else { + } + else + { if (!mWorldScene->isCellActive(*currCell)) copyObjectToCell(ptr, newCell, pos); else if (!mWorldScene->isCellActive(newCell)) @@ -732,8 +735,8 @@ namespace MWWorld MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->removeActor(ptr); - mechMgr->addActor(copy); + mechMgr->remove(ptr); + mechMgr->add(copy); } else { From fdabef65a1ccae23007a720a224d6e76dfd3ea12 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:19:24 -0800 Subject: [PATCH 458/916] Use a method to update an object's cell in the mechanics manager This prevents destroying and recreating the object's character controller (and messing up the current animation) when moving between cells. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 +++ apps/openmw/mwmechanics/activators.cpp | 11 ++++++++++ apps/openmw/mwmechanics/activators.hpp | 3 +++ apps/openmw/mwmechanics/actors.cpp | 11 ++++++++++ apps/openmw/mwmechanics/actors.hpp | 3 +++ .../mwmechanics/mechanicsmanagerimp.cpp | 9 ++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 22 +++++-------------- 8 files changed, 49 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index ec616fcaf..cb9539ef6 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -43,6 +43,9 @@ namespace MWBase virtual void remove (const MWWorld::Ptr& ptr) = 0; ///< Deregister an object for management + virtual void updateCell(const MWWorld::Ptr &ptr) = 0; + ///< Moves an object to a new cell + virtual void drop (const MWWorld::CellStore *cellStore) = 0; ///< Deregister all objects in the given cell. diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 799d7ecd5..20b7865f5 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -25,6 +25,17 @@ void Activators::removeActivator (const MWWorld::Ptr& ptr) mActivators.erase(iter); } +void Activators::updateActivatorCell(const MWWorld::Ptr &ptr) +{ + PtrControllerMap::iterator iter = mActivators.find(ptr); + if(iter != mActivators.end()) + { + CharacterController ctrl = iter->second; + mActivators.erase(iter); + mActivators.insert(std::make_pair(ptr, ctrl)); + } +} + void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) { PtrControllerMap::iterator iter = mActivators.begin(); diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 3ddb0f843..5c3eba220 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -28,6 +28,9 @@ namespace MWMechanics void removeActivator (const MWWorld::Ptr& ptr); ///< Deregister an activator + void updateActivatorCell(const MWWorld::Ptr& ptr); + ///< Updates an activator with a new cell store + void dropActivators (const MWWorld::CellStore *cellStore); ///< Deregister all activators in the given cell. diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 98ae3e755..27b7ad14e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -179,6 +179,17 @@ namespace MWMechanics mActors.erase(iter); } + void Actors::updateActorCell(const MWWorld::Ptr &ptr) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + { + CharacterController ctrl = iter->second; + mActors.erase(iter); + mActors.insert(std::make_pair(ptr, ctrl)); + } + } + void Actors::dropActors (const MWWorld::Ptr::CellStore *cellStore) { PtrControllerMap::iterator iter = mActors.begin(); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6fed9eff7..8c3df6c28 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -53,6 +53,9 @@ namespace MWMechanics /// /// \note Ignored, if \a ptr is not a registered actor. + void updateActorCell(const MWWorld::Ptr& ptr); + ///< Updates an actor with a new cell store + void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3e56cbcb1..9e76084f5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -190,6 +190,15 @@ namespace MWMechanics mActors.removeActor(ptr); } + void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) + { + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + mActivators.updateActivatorCell(ptr); + else + mActors.updateActorCell(ptr); + } + + void MechanicsManager::drop(const MWWorld::CellStore *cellStore) { if(!mWatched.isEmpty() && mWatched.getCell() == cellStore) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f70242bb9..99010b7ff 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -48,6 +48,9 @@ namespace MWMechanics virtual void remove (const MWWorld::Ptr& ptr); ///< Deregister an object for management + virtual void updateCell(const MWWorld::Ptr &ptr); + ///< Moves an object to a new cell + virtual void drop(const MWWorld::CellStore *cellStore); ///< Deregister all objects in the given cell. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a1d713a8a..84a6b1b3d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -729,24 +729,14 @@ namespace MWWorld addContainerScripts(copy, &newCell); mRendering->moveObjectToCell(copy, vec, currCell); + MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); + mechMgr->updateCell(copy); - if (MWWorld::Class::get(ptr).isActor()) + std::string script = MWWorld::Class::get(ptr).getScript(ptr); + if(!script.empty()) { - MWBase::MechanicsManager *mechMgr = - MWBase::Environment::get().getMechanicsManager(); - - mechMgr->remove(ptr); - mechMgr->add(copy); - } - else - { - std::string script = - MWWorld::Class::get(ptr).getScript(ptr); - if (!script.empty()) - { - mLocalScripts.remove(ptr); - mLocalScripts.add(script, copy); - } + mLocalScripts.remove(ptr); + mLocalScripts.add(script, copy); } } ptr.getRefData().setCount(0); From 92d0c55f32bf9e2ee8d6a850bdd4b2d4e4fff82c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:43:42 -0800 Subject: [PATCH 459/916] Add a flag to specify if an animation should be playing --- apps/openmw/mwrender/animation.cpp | 13 ++++++++++--- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c4439841f..b0f21da84 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mAnimState(NULL) + , mPlaying(false) , mLooping(false) , mAnimSpeedMult(1.0f) { @@ -187,6 +188,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; reset(start); + mPlaying = true; } catch(std::exception &e) { std::cerr<< e.what() < 0.0f) + while(mAnimState && mPlaying && timepassed > 0.0f) { float targetTime = mAnimState->getTimePosition() + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); + mPlaying = (targetTime < mAnimState->getLength() || mLooping); break; } @@ -236,8 +239,12 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mAnimState->getTimePosition() >= time) break; } - else if(mController) - mController->markerEvent(time, evt); + else + { + mPlaying = false; + if(mController) + mController->markerEvent(time, evt); + } continue; } if(mController) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ed9c6eb19..091c2f227 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -31,6 +31,7 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; + bool mPlaying; bool mLooping; float mAnimSpeedMult; From 879359f39d35cc88724b251231543bc76bda0bd1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 00:50:52 -0800 Subject: [PATCH 460/916] Set the animation state loop flag as appropriate --- apps/openmw/mwrender/animation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b0f21da84..9666e62f4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -184,6 +184,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); mAnimState->setEnabled(true); + mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; mLooping = loop; From 99efe4e494f449950877e08ca93a9d43a99adc1b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:02:55 -0800 Subject: [PATCH 461/916] Remove an unnecessary class member --- apps/openmw/mwrender/animation.cpp | 8 +++----- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9666e62f4..778efc813 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -27,7 +27,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentKeys(NULL) , mAnimState(NULL) , mPlaying(false) - , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -187,7 +186,6 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; - mLooping = loop; reset(start); mPlaying = true; } @@ -206,7 +204,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (targetTime < mAnimState->getLength() || mLooping); + mPlaying = (mAnimState->getLoop() || mAnimState->getLength() >= targetTime); break; } @@ -224,7 +222,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "loop stop") { - if(mLooping) + if(mAnimState->getLoop()) { reset("loop start"); if(mAnimState->getTimePosition() >= time) @@ -234,7 +232,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "stop") { - if(mLooping) + if(mAnimState->getLoop()) { reset("loop start"); if(mAnimState->getTimePosition() >= time) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 091c2f227..5fa1bd85c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -32,7 +32,6 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::AnimationState *mAnimState; bool mPlaying; - bool mLooping; float mAnimSpeedMult; From d4ddaa3d9585411c9f7c7a8a90e12de2ce517db0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:08:52 -0800 Subject: [PATCH 462/916] Only register activators that have a MWRender::Animation object --- apps/openmw/mwmechanics/activators.cpp | 5 +++-- apps/openmw/mwmechanics/activators.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 20b7865f5..1a743cad5 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -12,10 +12,11 @@ Activators::Activators() { } -void Activators::addActivator (const MWWorld::Ptr& ptr) +void Activators::addActivator(const MWWorld::Ptr& ptr) { MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); + if(anim != NULL) + mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); } void Activators::removeActivator (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 5c3eba220..0b9e984aa 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -23,7 +23,7 @@ namespace MWMechanics Activators(); void addActivator (const MWWorld::Ptr& ptr); - ///< Register an activator + ///< Register an animated activator void removeActivator (const MWWorld::Ptr& ptr); ///< Deregister an activator From 0853fa335c2545a7ada380315b18078736d72ed6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 01:36:17 -0800 Subject: [PATCH 463/916] Avoid redundant string concatenations --- components/nifogre/ogre_nif_loader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8dbfbff5a..d1bf803f1 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1204,14 +1204,14 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen return entitylist; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = bonename; + std::string filter = "@shape=tri "+bonename; Misc::StringUtils::toLower(filter); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); if(ent->hasSkeleton()) { - if(meshes[i].mMeshName.find("@shape=tri "+filter) == std::string::npos) + if(meshes[i].mMeshName.find(filter) == std::string::npos) { sceneMgr->destroyEntity(ent); continue; From 04d4c125ba85775c8ca8e1c17e5f7122fbab444c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 29 Jan 2013 02:00:42 -0800 Subject: [PATCH 464/916] Print when an animation event is unhandled --- apps/openmw/mwmechanics/character.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 83326d25a..6e78adfa4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -122,6 +122,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) } return; } + + std::cerr<< "Unhandled animation event: "< Date: Wed, 30 Jan 2013 02:38:50 -0800 Subject: [PATCH 465/916] Make sure the player node's visibility cascades --- apps/openmw/mwrender/player.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 8f3e13039..9ab8a7de3 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -129,11 +129,8 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - mPlayerNode->setVisible( - mVanity.enabled || mPreviewMode || !mFirstPersonView, - false - ); - + /// \fixme We shouldn't hide the whole model, just certain components of the character (head, chest, feet, etc) + mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); if (mFirstPersonView && !mVanity.enabled) { return; } @@ -310,10 +307,7 @@ namespace MWRender delete mAnimation; mAnimation = anim; - mPlayerNode->setVisible( - mVanity.enabled || mPreviewMode || !mFirstPersonView, - false - ); + mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); } void Player::setHeight(float height) From 360f7bfac88a3d1346691eb8d6896b61125bf9ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 07:04:18 -0800 Subject: [PATCH 466/916] Apply animations to bones manually Couple reasons for this: * This paves the way for allowing animations specified in other skeletons to be applied to the character (NPCs and certain creatures can have multiple animation sources, but Ogre is incredibly strict when it comes to sharing animations between skeletons). * It will allow for entities to be animated based on the character's skeleton, without having to duplicate the mesh for each skeleton it can be used on. This doesn't impact Ogre's ability to efficiently deform skinned meshes, nor does it get in the way of hardware skinning. --- apps/openmw/mwrender/animation.cpp | 61 ++++++++++++++++++------------ apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 778efc813..03bc92e96 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -94,24 +94,12 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model break; } - // Reset initial state of bones that are animated, so the animation correctly applies. - if(skelinst->getNumAnimations() > 0) - { - Ogre::Animation *anim = skelinst->getAnimation(0); - Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); - while(trackiter.hasMoreElements()) - { - const Ogre::Node *srcnode = trackiter.getNext()->getAssociatedNode(); - if(!skelinst->hasBone(srcnode->getName())) - continue; - - Ogre::Bone *bone = skelinst->getBone(srcnode->getName()); - bone->setOrientation(Ogre::Quaternion::IDENTITY); - bone->setPosition(Ogre::Vector3::ZERO); - bone->setScale(Ogre::Vector3(1.0f)); - bone->setInitialState(); - } - } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). + boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); } } @@ -134,16 +122,39 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) } +void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) +{ + Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); + Ogre::Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator(); + while(tracks.hasMoreElements()) + { + Ogre::NodeAnimationTrack *track = tracks.getNext(); + const Ogre::String &targetname = track->getAssociatedNode()->getName(); + if(!skel->hasBone(targetname)) + continue; + Ogre::Bone *bone = skel->getBone(targetname); + bone->setOrientation(Ogre::Quaternion::IDENTITY); + bone->setPosition(Ogre::Vector3::ZERO); + bone->setScale(Ogre::Vector3::UNIT_SCALE); + track->applyToNode(bone, timeindex); + } + + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); +} + + Ogre::Vector3 Animation::updatePosition(float time) { + Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); mAnimState->setTimePosition(time); + applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) { - /* Update the animation and get the non-accumulation root's difference from the - * last update. */ - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); + /* Get the non-accumulation root's difference from the last update. */ posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ @@ -159,6 +170,7 @@ void Animation::reset(const std::string &marker) while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; + Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); if(mNextKey != mCurrentKeys->end()) mAnimState->setTimePosition(mNextKey->first); else @@ -166,10 +178,10 @@ void Animation::reset(const std::string &marker) mNextKey = mCurrentKeys->begin(); mAnimState->setTimePosition(0.0f); } + applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); if(mNonAccumRoot) { - mEntityList.mSkelBase->getSkeleton()->setAnimationState(*mAnimState->getParent()); mLastPosition = mNonAccumRoot->getPosition(); mAccumRoot->setPosition(mStartPosition - mLastPosition); } @@ -179,10 +191,7 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - if(mAnimState) - mAnimState->setEnabled(false); mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mAnimState->setEnabled(true); mAnimState->setLoop(loop); mCurrentKeys = &mTextKeys[groupname]; @@ -197,6 +206,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo Ogre::Vector3 Animation::runAnimation(float timepassed) { Ogre::Vector3 movement = Ogre::Vector3::ZERO; + timepassed *= mAnimSpeedMult; while(mAnimState && mPlaying && timepassed > 0.0f) { @@ -249,6 +259,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mController) mController->markerEvent(time, evt); } + return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 5fa1bd85c..c281551c7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -35,6 +35,8 @@ protected: float mAnimSpeedMult; + void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); From 5c3a7f7d523192c95380f9ec92e51ea25eb09213 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 07:34:07 -0800 Subject: [PATCH 467/916] Avoid handling animation states We don't need them anymore --- apps/openmw/mwrender/animation.cpp | 41 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 4 ++- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 03bc92e96..73780a7f0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -25,8 +25,10 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) - , mAnimState(NULL) + , mCurrentAnim(NULL) + , mCurrentTime(0.0f) , mPlaying(false) + , mLooping(false) , mAnimSpeedMult(1.0f) { } @@ -106,7 +108,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model bool Animation::hasAnimation(const std::string &anim) { - return mEntityList.mSkelBase && mEntityList.mSkelBase->hasAnimationState(anim); + return mEntityList.mSkelBase && mEntityList.mSkelBase->getSkeleton()->hasAnimation(anim); } @@ -147,9 +149,11 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk Ogre::Vector3 Animation::updatePosition(float time) { - Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); - mAnimState->setTimePosition(time); - applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); + if(mLooping) + mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); + else + mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); + applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) @@ -170,15 +174,14 @@ void Animation::reset(const std::string &marker) while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) mNextKey++; - Ogre::SkeletonInstance *skel = mEntityList.mSkelBase->getSkeleton(); if(mNextKey != mCurrentKeys->end()) - mAnimState->setTimePosition(mNextKey->first); + mCurrentTime = mNextKey->first; else { mNextKey = mCurrentKeys->begin(); - mAnimState->setTimePosition(0.0f); + mCurrentTime = 0.0f; } - applyAnimation(skel->getAnimation(mAnimState->getAnimationName()), mAnimState->getTimePosition(), skel); + applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); if(mNonAccumRoot) { @@ -191,12 +194,12 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - mAnimState = mEntityList.mSkelBase->getAnimationState(groupname); - mAnimState->setLoop(loop); - + mCurrentAnim = mEntityList.mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + reset(start); mPlaying = true; + mLooping = loop; } catch(std::exception &e) { std::cerr<< e.what() < 0.0f) + while(mCurrentAnim && mPlaying && timepassed > 0.0f) { - float targetTime = mAnimState->getTimePosition() + timepassed; + float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (mAnimState->getLoop() || mAnimState->getLength() >= targetTime); + mPlaying = (mLooping || mCurrentAnim->getLength() >= targetTime); break; } @@ -232,20 +235,20 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) } if(evt == "loop stop") { - if(mAnimState->getLoop()) + if(mLooping) { reset("loop start"); - if(mAnimState->getTimePosition() >= time) + if(mCurrentTime >= time) break; } continue; } if(evt == "stop") { - if(mAnimState->getLoop()) + if(mLooping) { reset("loop start"); - if(mAnimState->getTimePosition() >= time) + if(mCurrentTime >= time) break; } else diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c281551c7..886d967ab 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -30,8 +30,10 @@ protected: NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; - Ogre::AnimationState *mAnimState; + Ogre::Animation *mCurrentAnim; + float mCurrentTime; bool mPlaying; + bool mLooping; float mAnimSpeedMult; From b6354c6282785feba4106a919242c491dcea3380 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 09:29:16 -0800 Subject: [PATCH 468/916] Don't share skeleton instances between bounded parts on an NPC However, a skeleton instance will still be shared between entities in an entity list. --- apps/openmw/mwrender/animation.cpp | 15 +++++++++++++++ apps/openmw/mwrender/animation.hpp | 5 +++++ apps/openmw/mwrender/npcanimation.cpp | 26 +++++++++++++++++++++++++- components/nifogre/ogre_nif_loader.cpp | 5 ++--- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 73780a7f0..b63de2f16 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -146,6 +146,21 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } +void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel) +{ + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.getNext(); + if(!skelsrc->hasBone(bone->getName())) + continue; + Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); + bone->setOrientation(srcbone->getOrientation()); + bone->setPosition(srcbone->getPosition()); + bone->setScale(srcbone->getScale()); + } +} + Ogre::Vector3 Animation::updatePosition(float time) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 886d967ab..60e524d28 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -37,8 +37,13 @@ protected: float mAnimSpeedMult; + /* Applies the given animation to the given skeleton instance, using the specified time. */ void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); + /* Updates a skeleton instance so that all bones matching the source skeleton (based on + * bone names) are positioned identically. */ + void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 432a2f526..03fda8982 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -305,6 +305,21 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); } + if(entities.mSkelBase) + { + Ogre::AnimationStateSet *aset = entities.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) + { + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); + } + Ogre::SkeletonInstance *skelinst = entities.mSkelBase->getSkeleton(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); + } return entities; } @@ -317,7 +332,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) } mTimeToChange += timepassed; - return Animation::runAnimation(timepassed); + Ogre::Vector3 ret = Animation::runAnimation(timepassed); + const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); + for(size_t i = 0;i < sPartListSize;i++) + { + Ogre::Entity *ent = (this->*sPartList[i].ents).mSkelBase; + if(!ent) continue; + updateSkeletonInstance(skelsrc, ent->getSkeleton()); + ent->getAllAnimationStates()->_notifyDirty(); + } + return ret; } void NpcAnimation::removeEntities(NifOgre::EntityList &entities) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index d1bf803f1..5444c803b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1228,19 +1228,18 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(entitylist.mSkelBase) { - entitylist.mSkelBase->shareSkeletonInstanceWith(parent); parentNode->attachObject(entitylist.mSkelBase); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity != entitylist.mSkelBase && entity->hasSkeleton()) { - entity->shareSkeletonInstanceWith(parent); + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) { - Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(bonename, entity); tag->setScale(scale); } } From f029a9011aea60f54ad63617cb9eaf3613ee72b0 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sun, 27 Jan 2013 22:40:38 +0100 Subject: [PATCH 469/916] Move datafilespage to shared space. --- apps/launcher/CMakeLists.txt | 33 ------------------- apps/launcher/graphicspage.cpp | 3 +- apps/launcher/maindialog.cpp | 3 +- cmake/OpenMWMacros.cmake | 16 +++++++++ components/CMakeLists.txt | 12 ++++++- .../file_order_list}/datafilespage.cpp | 0 .../file_order_list}/datafilespage.hpp | 0 .../file_order_list}/model/datafilesmodel.cpp | 0 .../file_order_list}/model/datafilesmodel.hpp | 0 .../file_order_list}/model/esm/esmfile.cpp | 0 .../file_order_list}/model/esm/esmfile.hpp | 0 .../file_order_list}/model/modelitem.cpp | 0 .../file_order_list}/model/modelitem.hpp | 0 .../file_order_list}/utils/filedialog.cpp | 0 .../file_order_list}/utils/filedialog.hpp | 0 .../file_order_list}/utils/lineedit.cpp | 0 .../file_order_list}/utils/lineedit.hpp | 0 .../file_order_list}/utils/naturalsort.cpp | 0 .../file_order_list}/utils/naturalsort.hpp | 0 .../utils/profilescombobox.cpp | 0 .../utils/profilescombobox.hpp | 0 .../utils/textinputdialog.cpp | 0 .../utils/textinputdialog.hpp | 0 23 files changed, 30 insertions(+), 37 deletions(-) rename {apps/launcher => components/file_order_list}/datafilespage.cpp (100%) rename {apps/launcher => components/file_order_list}/datafilespage.hpp (100%) rename {apps/launcher => components/file_order_list}/model/datafilesmodel.cpp (100%) rename {apps/launcher => components/file_order_list}/model/datafilesmodel.hpp (100%) rename {apps/launcher => components/file_order_list}/model/esm/esmfile.cpp (100%) rename {apps/launcher => components/file_order_list}/model/esm/esmfile.hpp (100%) rename {apps/launcher => components/file_order_list}/model/modelitem.cpp (100%) rename {apps/launcher => components/file_order_list}/model/modelitem.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/filedialog.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/filedialog.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/lineedit.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/lineedit.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/naturalsort.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/naturalsort.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/profilescombobox.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/profilescombobox.hpp (100%) rename {apps/launcher => components/file_order_list}/utils/textinputdialog.cpp (100%) rename {apps/launcher => components/file_order_list}/utils/textinputdialog.hpp (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 09beaf59d..73efb9ee5 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -1,56 +1,23 @@ set(LAUNCHER - datafilespage.cpp graphicspage.cpp main.cpp maindialog.cpp playpage.cpp - model/datafilesmodel.cpp - model/modelitem.cpp - model/esm/esmfile.cpp - - utils/filedialog.cpp - utils/naturalsort.cpp - utils/lineedit.cpp - utils/profilescombobox.cpp - utils/textinputdialog.cpp - launcher.rc ) set(LAUNCHER_HEADER - datafilespage.hpp graphicspage.hpp maindialog.hpp playpage.hpp - - model/datafilesmodel.hpp - model/modelitem.hpp - model/esm/esmfile.hpp - - utils/lineedit.hpp - utils/filedialog.hpp - utils/naturalsort.hpp - utils/profilescombobox.hpp - utils/textinputdialog.hpp - ) # Headers that must be pre-processed set(LAUNCHER_HEADER_MOC - datafilespage.hpp graphicspage.hpp maindialog.hpp playpage.hpp - - model/datafilesmodel.hpp - model/modelitem.hpp - model/esm/esmfile.hpp - - utils/lineedit.hpp - utils/filedialog.hpp - utils/profilescombobox.hpp - utils/textinputdialog.hpp ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 2c4f3430c..e69a8c207 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -8,8 +8,7 @@ #include #include #include - -#include "utils/naturalsort.hpp" +#include #include "graphicspage.hpp" diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 674ccdf67..7eb31e76b 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,9 +1,10 @@ #include +#include + #include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" -#include "datafilespage.hpp" MainDialog::MainDialog() { diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index e6f45fdb1..398363667 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -23,6 +23,22 @@ endforeach (u) source_group ("components\\${dir}" FILES ${files}) endmacro (add_component_dir) +macro (add_component_qt_dir dir) +set (files) +foreach (u ${ARGN}) +file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +foreach (f ${ALL}) +list (APPEND files "${f}") +list (APPEND COMPONENT_FILES "${f}") +endforeach (f) +file (GLOB MOC_H ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.hpp") +foreach (fi ${MOC_H}) +list (APPEND COMPONENT_MOC_FILES "${fi}") +endforeach (fi) +endforeach (u) +source_group ("components\\${dir}" FILES ${files}) +endmacro (add_component_qt_dir) + macro (copy_all_files source_dir destination_dir files) foreach (f ${files}) get_filename_component(filename ${f} NAME) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3da09ecb8..a6812dbb3 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -66,9 +66,19 @@ add_component_dir (translation translation ) +add_component_qt_dir (file_order_list + datafilespage model/modelitem model/datafilesmodel model/esm/esmfile + utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort + ) + +find_package(Qt4 COMPONENTS QtCore QtGUI REQUIRED) +include(${QT_USE_FILE}) + +QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + include_directories(${BULLET_INCLUDE_DIRS}) -add_library(components STATIC ${COMPONENT_FILES}) +add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS}) target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) diff --git a/apps/launcher/datafilespage.cpp b/components/file_order_list/datafilespage.cpp similarity index 100% rename from apps/launcher/datafilespage.cpp rename to components/file_order_list/datafilespage.cpp diff --git a/apps/launcher/datafilespage.hpp b/components/file_order_list/datafilespage.hpp similarity index 100% rename from apps/launcher/datafilespage.hpp rename to components/file_order_list/datafilespage.hpp diff --git a/apps/launcher/model/datafilesmodel.cpp b/components/file_order_list/model/datafilesmodel.cpp similarity index 100% rename from apps/launcher/model/datafilesmodel.cpp rename to components/file_order_list/model/datafilesmodel.cpp diff --git a/apps/launcher/model/datafilesmodel.hpp b/components/file_order_list/model/datafilesmodel.hpp similarity index 100% rename from apps/launcher/model/datafilesmodel.hpp rename to components/file_order_list/model/datafilesmodel.hpp diff --git a/apps/launcher/model/esm/esmfile.cpp b/components/file_order_list/model/esm/esmfile.cpp similarity index 100% rename from apps/launcher/model/esm/esmfile.cpp rename to components/file_order_list/model/esm/esmfile.cpp diff --git a/apps/launcher/model/esm/esmfile.hpp b/components/file_order_list/model/esm/esmfile.hpp similarity index 100% rename from apps/launcher/model/esm/esmfile.hpp rename to components/file_order_list/model/esm/esmfile.hpp diff --git a/apps/launcher/model/modelitem.cpp b/components/file_order_list/model/modelitem.cpp similarity index 100% rename from apps/launcher/model/modelitem.cpp rename to components/file_order_list/model/modelitem.cpp diff --git a/apps/launcher/model/modelitem.hpp b/components/file_order_list/model/modelitem.hpp similarity index 100% rename from apps/launcher/model/modelitem.hpp rename to components/file_order_list/model/modelitem.hpp diff --git a/apps/launcher/utils/filedialog.cpp b/components/file_order_list/utils/filedialog.cpp similarity index 100% rename from apps/launcher/utils/filedialog.cpp rename to components/file_order_list/utils/filedialog.cpp diff --git a/apps/launcher/utils/filedialog.hpp b/components/file_order_list/utils/filedialog.hpp similarity index 100% rename from apps/launcher/utils/filedialog.hpp rename to components/file_order_list/utils/filedialog.hpp diff --git a/apps/launcher/utils/lineedit.cpp b/components/file_order_list/utils/lineedit.cpp similarity index 100% rename from apps/launcher/utils/lineedit.cpp rename to components/file_order_list/utils/lineedit.cpp diff --git a/apps/launcher/utils/lineedit.hpp b/components/file_order_list/utils/lineedit.hpp similarity index 100% rename from apps/launcher/utils/lineedit.hpp rename to components/file_order_list/utils/lineedit.hpp diff --git a/apps/launcher/utils/naturalsort.cpp b/components/file_order_list/utils/naturalsort.cpp similarity index 100% rename from apps/launcher/utils/naturalsort.cpp rename to components/file_order_list/utils/naturalsort.cpp diff --git a/apps/launcher/utils/naturalsort.hpp b/components/file_order_list/utils/naturalsort.hpp similarity index 100% rename from apps/launcher/utils/naturalsort.hpp rename to components/file_order_list/utils/naturalsort.hpp diff --git a/apps/launcher/utils/profilescombobox.cpp b/components/file_order_list/utils/profilescombobox.cpp similarity index 100% rename from apps/launcher/utils/profilescombobox.cpp rename to components/file_order_list/utils/profilescombobox.cpp diff --git a/apps/launcher/utils/profilescombobox.hpp b/components/file_order_list/utils/profilescombobox.hpp similarity index 100% rename from apps/launcher/utils/profilescombobox.hpp rename to components/file_order_list/utils/profilescombobox.hpp diff --git a/apps/launcher/utils/textinputdialog.cpp b/components/file_order_list/utils/textinputdialog.cpp similarity index 100% rename from apps/launcher/utils/textinputdialog.cpp rename to components/file_order_list/utils/textinputdialog.cpp diff --git a/apps/launcher/utils/textinputdialog.hpp b/components/file_order_list/utils/textinputdialog.hpp similarity index 100% rename from apps/launcher/utils/textinputdialog.hpp rename to components/file_order_list/utils/textinputdialog.hpp From ac62dd050d31066ed1c40655bd167e22ff5d2b81 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Wed, 30 Jan 2013 21:08:27 +0100 Subject: [PATCH 470/916] Rename datafilespage to datafileslist --- apps/launcher/maindialog.cpp | 20 +++++----- apps/launcher/maindialog.hpp | 4 +- components/CMakeLists.txt | 2 +- .../{datafilespage.cpp => datafileslist.cpp} | 38 +++++++++---------- .../{datafilespage.hpp => datafileslist.hpp} | 8 ++-- 5 files changed, 36 insertions(+), 36 deletions(-) rename components/file_order_list/{datafilespage.cpp => datafileslist.cpp} (97%) rename components/file_order_list/{datafilespage.hpp => datafileslist.hpp} (92%) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 7eb31e76b..43b8f317a 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include "maindialog.hpp" #include "playpage.hpp" @@ -124,16 +124,16 @@ void MainDialog::createPages() { mPlayPage = new PlayPage(this); mGraphicsPage = new GraphicsPage(mCfgMgr, this); - mDataFilesPage = new DataFilesPage(mCfgMgr, this); + mDataFilesList = new DataFilesList(mCfgMgr, this); // Set the combobox of the play page to imitate the combobox on the datafilespage - mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); - mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); + mPlayPage->mProfilesComboBox->setModel(mDataFilesList->mProfilesComboBox->model()); + mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesList->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget mPagesWidget->addWidget(mPlayPage); mPagesWidget->addWidget(mGraphicsPage); - mPagesWidget->addWidget(mDataFilesPage); + mPagesWidget->addWidget(mDataFilesList); // Select the first page mIconWidget->setCurrentItem(mIconWidget->item(0), QItemSelectionModel::Select); @@ -142,9 +142,9 @@ void MainDialog::createPages() connect(mPlayPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), - mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); + mDataFilesList->mProfilesComboBox, SLOT(setCurrentIndex(int))); - connect(mDataFilesPage->mProfilesComboBox, + connect(mDataFilesList->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); @@ -190,7 +190,7 @@ bool MainDialog::setup() } // Setup the Data Files page - if (!mDataFilesPage->setupDataFiles()) { + if (!mDataFilesList->setupDataFiles()) { return false; } @@ -208,7 +208,7 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) void MainDialog::closeEvent(QCloseEvent *event) { // Now write all config files - mDataFilesPage->writeConfig(); + mDataFilesList->writeConfig(); mGraphicsPage->writeConfig(); // Save user settings @@ -221,7 +221,7 @@ void MainDialog::closeEvent(QCloseEvent *event) void MainDialog::play() { // First do a write of all the configs, just to be sure - mDataFilesPage->writeConfig(); + mDataFilesList->writeConfig(); mGraphicsPage->writeConfig(); // Save user settings diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index bf98011cc..5a39c11a9 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -15,7 +15,7 @@ class QString; class PlayPage; class GraphicsPage; -class DataFilesPage; +class DataFilesList; class MainDialog : public QMainWindow { @@ -39,7 +39,7 @@ private: PlayPage *mPlayPage; GraphicsPage *mGraphicsPage; - DataFilesPage *mDataFilesPage; + DataFilesList *mDataFilesList; Files::ConfigurationManager mCfgMgr; Settings::Manager mSettings; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a6812dbb3..3798f66b7 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -67,7 +67,7 @@ add_component_dir (translation ) add_component_qt_dir (file_order_list - datafilespage model/modelitem model/datafilesmodel model/esm/esmfile + datafileslist model/modelitem model/datafilesmodel model/esm/esmfile utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort ) diff --git a/components/file_order_list/datafilespage.cpp b/components/file_order_list/datafileslist.cpp similarity index 97% rename from components/file_order_list/datafilespage.cpp rename to components/file_order_list/datafileslist.cpp index 6b0539c1d..bf4f8cb86 100644 --- a/components/file_order_list/datafilespage.cpp +++ b/components/file_order_list/datafileslist.cpp @@ -12,7 +12,7 @@ #include "utils/naturalsort.hpp" #include "utils/textinputdialog.hpp" -#include "datafilespage.hpp" +#include "datafileslist.hpp" #include /** @@ -46,7 +46,7 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) return index1.row() <= index2.row(); } -DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) +DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) : QWidget(parent) , mCfgMgr(cfg) { @@ -180,7 +180,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) setupConfig(); } -void DataFilesPage::createActions() +void DataFilesList::createActions() { // Refresh the plugins QAction *refreshAction = new QAction(tr("Refresh"), this); @@ -218,7 +218,7 @@ void DataFilesPage::createActions() } -void DataFilesPage::setupConfig() +void DataFilesList::setupConfig() { // Open our config file QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); @@ -265,7 +265,7 @@ void DataFilesPage::setupConfig() } -void DataFilesPage::readConfig() +void DataFilesList::readConfig() { // Don't read the config if no masters are found if (mMastersModel->rowCount() < 1) @@ -340,7 +340,7 @@ void DataFilesPage::readConfig() } -bool DataFilesPage::showDataFilesWarning() +bool DataFilesList::showDataFilesWarning() { QMessageBox msgBox; @@ -381,7 +381,7 @@ bool DataFilesPage::showDataFilesWarning() return true; } -bool DataFilesPage::setupDataFiles() +bool DataFilesList::setupDataFiles() { // We use the Configuration Manager to retrieve the configuration values boost::program_options::variables_map variables; @@ -451,7 +451,7 @@ bool DataFilesPage::setupDataFiles() return true; } -void DataFilesPage::writeConfig(QString profile) +void DataFilesList::writeConfig(QString profile) { // Don't overwrite the config if no masters are found if (mMastersModel->rowCount() < 1) @@ -606,7 +606,7 @@ void DataFilesPage::writeConfig(QString profile) } -void DataFilesPage::newProfile() +void DataFilesList::newProfile() { if (mNewProfileDialog->exec() == QDialog::Accepted) { @@ -621,7 +621,7 @@ void DataFilesPage::newProfile() } } -void DataFilesPage::updateOkButton(const QString &text) +void DataFilesList::updateOkButton(const QString &text) { if (text.isEmpty()) { mNewProfileDialog->setOkButtonEnabled(false); @@ -633,7 +633,7 @@ void DataFilesPage::updateOkButton(const QString &text) : mNewProfileDialog->setOkButtonEnabled(false); } -void DataFilesPage::deleteProfile() +void DataFilesList::deleteProfile() { QString profile = mProfilesComboBox->currentText(); @@ -670,7 +670,7 @@ void DataFilesPage::deleteProfile() } } -void DataFilesPage::check() +void DataFilesList::check() { // Check the current selection if (!mPluginsTable->selectionModel()->hasSelection()) { @@ -690,7 +690,7 @@ void DataFilesPage::check() } } -void DataFilesPage::uncheck() +void DataFilesList::uncheck() { // uncheck the current selection if (!mPluginsTable->selectionModel()->hasSelection()) { @@ -710,7 +710,7 @@ void DataFilesPage::uncheck() } } -void DataFilesPage::refresh() +void DataFilesList::refresh() { mPluginsModel->sort(0); @@ -722,7 +722,7 @@ void DataFilesPage::refresh() } -void DataFilesPage::setCheckState(QModelIndex index) +void DataFilesList::setCheckState(QModelIndex index) { if (!index.isValid()) return; @@ -751,13 +751,13 @@ void DataFilesPage::setCheckState(QModelIndex index) } -void DataFilesPage::filterChanged(const QString filter) +void DataFilesList::filterChanged(const QString filter) { QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); mPluginsProxyModel->setFilterRegExp(regExp); } -void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) +void DataFilesList::profileChanged(const QString &previous, const QString ¤t) { qDebug() << "Profile is changed from: " << previous << " to " << current; // Prevent the deletion of the default profile @@ -785,7 +785,7 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre readConfig(); } -void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) +void DataFilesList::profileRenamed(const QString &previous, const QString ¤t) { if (previous.isEmpty()) return; @@ -815,7 +815,7 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre readConfig(); } -void DataFilesPage::showContextMenu(const QPoint &point) +void DataFilesList::showContextMenu(const QPoint &point) { // Make sure there are plugins in the view if (!mPluginsTable->selectionModel()->hasSelection()) { diff --git a/components/file_order_list/datafilespage.hpp b/components/file_order_list/datafileslist.hpp similarity index 92% rename from components/file_order_list/datafilespage.hpp rename to components/file_order_list/datafileslist.hpp index 13668ec30..7bb6605ab 100644 --- a/components/file_order_list/datafilespage.hpp +++ b/components/file_order_list/datafileslist.hpp @@ -1,5 +1,5 @@ -#ifndef DATAFILESPAGE_H -#define DATAFILESPAGE_H +#ifndef DATAFILESLIST_H +#define DATAFILESLIST_H #include #include @@ -20,12 +20,12 @@ class TextInputDialog; namespace Files { struct ConfigurationManager; } -class DataFilesPage : public QWidget +class DataFilesList : public QWidget { Q_OBJECT public: - DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); + DataFilesList(Files::ConfigurationManager& cfg, QWidget *parent = 0); ProfilesComboBox *mProfilesComboBox; From dc91211b12f7fa6b4b9c0bdd505f2618ed8125fc Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 00:21:04 +0000 Subject: [PATCH 471/916] Fixed Small bug where scripts were being removed when they shouldn't be. Scripts should only be removed when the item is being moved to another cell, otherwise they should remain active. --- apps/openmw/mwworld/worldimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 24d139b37..ddcace338 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -694,10 +694,11 @@ namespace MWWorld bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; - removeContainerScripts(ptr); if (*currCell != newCell) { + removeContainerScripts(ptr); + if (isPlayer) if (!newCell.isExterior()) changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.mCell->mName), pos); From 09f9557ecb516a0a4d0d3db5e0364712a0c21b8a Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 00:34:16 +0000 Subject: [PATCH 472/916] Implemented OnPCEquip special variable --- apps/openmw/mwworld/actionequip.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 60260a812..c519a3ee5 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -3,6 +3,9 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/scriptmanager.hpp" + +#include #include "inventorystore.hpp" #include "player.hpp" @@ -35,6 +38,8 @@ namespace MWWorld std::string npcRace = actor.get()->mBase->mRace; + bool equipped = false; + // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) @@ -91,6 +96,7 @@ namespace MWWorld if (slot == --slots.first.end()) { invStore.equip(*slot, it); + equipped = true; break; } @@ -98,8 +104,16 @@ namespace MWWorld { // slot is not occupied invStore.equip(*slot, it); + equipped = true; break; } } + + /* Set OnPCEquip Variable on item's script, if it has a script with that variable declared */ + if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && MWWorld::Class::get(*it).getScript(*it) != ""){ + int index = MWBase::Environment::get().getScriptManager()->getLocals(MWWorld::Class::get(*it).getScript(*it)).getIndex("onpcequip"); + if(index != -1) + (*it).mRefData->getLocals().mShorts.at (index) = 1; + } } } From d6f923f2743afd4bd781e5a31bc5f897f3f18785 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 22:28:18 -0800 Subject: [PATCH 473/916] Use a child scene node for the accumulation root --- apps/openmw/mwrender/animation.cpp | 5 ++--- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b63de2f16..b81104067 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node; + mInsert = node->createChildSceneNode(); assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,8 +76,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); + mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 60e524d28..165a6525c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Bone *mAccumRoot; + Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From c6a9ea50076765f26eee02616a9531ff95815133 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 30 Jan 2013 22:37:39 -0800 Subject: [PATCH 474/916] Use the skeleton as defined in the NIF model The avoids having to duplicate models that get attached to different character skeletons. --- components/nifogre/ogre_nif_loader.cpp | 59 ++++++++++++++------------ components/nifogre/ogre_nif_loader.hpp | 2 +- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5444c803b..9c9fd3b22 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -754,7 +754,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mName; std::string mGroup; size_t mShapeIndex; - std::string mSkelName; std::string mMaterialName; std::string mShapeName; @@ -782,11 +781,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be // explicitly attached later. - mesh->setSkeletonName(mSkelName); + mesh->setSkeletonName(mName); // Get the skeleton resource, so vertices can be transformed into the bones' initial state. Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - skel = skelMgr->getByName(mSkelName); + skel = skelMgr->getByName(mName); // Convert vertices and normals to bone space from bind position. It would be // better to transform the bones into bind position, but there doesn't seem to @@ -823,22 +822,26 @@ class NIFMeshLoader : Ogre::ManualResourceLoader srcVerts = newVerts; srcNorms = newNorms; } - else if(mSkelName.length() == 0) + else { - // No skinning and no skeleton, so just transform the vertices and - // normals into position. - Ogre::Matrix4 mat4 = shape->getWorldTransform(); - for(size_t i = 0;i < srcVerts.size();i++) + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(skelMgr->getByName(mName).isNull()) { - Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); - vec4 = mat4*vec4; - srcVerts[i] = Ogre::Vector3(&vec4[0]); - } - for(size_t i = 0;i < srcNorms.size();i++) - { - Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); - vec4 = mat4*vec4; - srcNorms[i] = Ogre::Vector3(&vec4[0]); + // No skinning and no skeleton, so just transform the vertices and + // normals into position. + Ogre::Matrix4 mat4 = shape->getWorldTransform(); + for(size_t i = 0;i < srcVerts.size();i++) + { + Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); + vec4 = mat4*vec4; + srcVerts[i] = Ogre::Vector3(&vec4[0]); + } + for(size_t i = 0;i < srcNorms.size();i++) + { + Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); + vec4 = mat4*vec4; + srcNorms[i] = Ogre::Vector3(&vec4[0]); + } } } @@ -998,8 +1001,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader public: NIFMeshLoader() { } - NIFMeshLoader(const std::string &name, const std::string &group, const std::string skelName) - : mName(name), mGroup(group), mShapeIndex(~(size_t)0), mSkelName(skelName) + NIFMeshLoader(const std::string &name, const std::string &group) + : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } virtual void loadResource(Ogre::Resource *resource) @@ -1010,7 +1013,9 @@ public: Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); if(mShapeIndex >= nif->numRecords()) { - mesh->setSkeletonName(mSkelName); + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(!skelMgr->getByName(mName).isNull()) + mesh->setSkeletonName(mName); return; } @@ -1061,8 +1066,6 @@ public: std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); if(mShapeName.length() > 0) fullname += "@shape="+mShapeName; - if(mSkelName.length() > 0 && mName != mSkelName) - fullname += "@skel="+mSkelName; Misc::StringUtils::toLower(fullname); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); @@ -1105,13 +1108,13 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; typedef std::map MeshInfoMap; static MeshInfoMap sMeshInfoMap; -MeshInfoList Loader::load(const std::string &name, const std::string &skelName, const std::string &group) +MeshInfoList Loader::load(const std::string &name, const std::string &group) { - MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name+"@skel="+skelName); + MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name); if(meshiter != sMeshInfoMap.end()) return meshiter->second; - MeshInfoList &meshes = sMeshInfoMap[name+"@skel="+skelName]; + MeshInfoList &meshes = sMeshInfoMap[name]; Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); if(nif.numRecords() < 1) @@ -1139,7 +1142,7 @@ MeshInfoList Loader::load(const std::string &name, const std::string &skelName, hasSkel = skelldr.createSkeleton(name, group, node); } - NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); + NIFMeshLoader meshldr(name, group); meshldr.createMeshes(node, meshes); return meshes; @@ -1150,7 +1153,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, name, group); + MeshInfoList meshes = load(name, group); if(meshes.size() == 0) return entitylist; @@ -1199,7 +1202,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, parent->getMesh()->getSkeletonName(), group); + MeshInfoList meshes = load(name, group); if(meshes.size() == 0) return entitylist; diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index f87d7d3c2..13a76d472 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -66,7 +66,7 @@ typedef std::vector MeshInfoList; class Loader { - static MeshInfoList load(const std::string &name, const std::string &skelName, const std::string &group); + static MeshInfoList load(const std::string &name, const std::string &group); public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, From 0fc5ee5149534facb779c4eed37f6f8f565856c2 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 17:46:16 +0000 Subject: [PATCH 475/916] allow OnPCEquip special variable to be of any type --- apps/openmw/mwworld/actionequip.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index c519a3ee5..2b238ead9 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -109,11 +109,28 @@ namespace MWWorld } } - /* Set OnPCEquip Variable on item's script, if it has a script with that variable declared */ - if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && MWWorld::Class::get(*it).getScript(*it) != ""){ - int index = MWBase::Environment::get().getScriptManager()->getLocals(MWWorld::Class::get(*it).getScript(*it)).getIndex("onpcequip"); + std::string script = MWWorld::Class::get(*it).getScript(*it); + + /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ + if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") + { + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex("onpcequip"); + char type = locals.getType("onpcequip"); if(index != -1) - (*it).mRefData->getLocals().mShorts.at (index) = 1; + { + switch(type) + { + case 's': + (*it).mRefData->getLocals().mShorts.at (index) = 1; break; + + case 'l': + (*it).mRefData->getLocals().mLongs.at (index) = 1; break; + + case 'f': + (*it).mRefData->getLocals().mFloats.at (index) = 1.0; break; + } + } } } } From 9ad08520fd766e45514e479a2f8ff866be3995b6 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 18:45:32 +0000 Subject: [PATCH 476/916] Implemented OnPCDrop special variable Scripts are responsible for resetting to 0, as investigation showed that is how vanilla handled it. --- apps/openmw/mwworld/worldimp.cpp | 44 ++++++++++++++++++++++++++++---- apps/openmw/mwworld/worldimp.hpp | 5 ++-- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ddcace338..0c8027975 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2,11 +2,13 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" @@ -1271,6 +1273,33 @@ namespace MWWorld mRendering->toggleWater(); } + void World::PCDropped (const Ptr& item) + { + std::string script = MWWorld::Class::get(item).getScript(item); + + /* Set OnPCDrop Variable on item's script, if it has a script with that variable declared */ + if(script != "") + { + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex("onpcdrop"); + char type = locals.getType("onpcdrop"); + if(index != -1) + { + switch(type) + { + case 's': + item.mRefData->getLocals().mShorts.at (index) = 1; break; + + case 'l': + item.mRefData->getLocals().mLongs.at (index) = 1; break; + + case 'f': + item.mRefData->getLocals().mFloats.at (index) = 1.0; break; + } + } + } + } + bool World::placeObject (const Ptr& object, float cursorX, float cursorY) { std::pair result = mPhysics->castRay(cursorX, cursorY); @@ -1293,9 +1322,10 @@ namespace MWWorld pos.pos[1] = -result.second[2]; pos.pos[2] = result.second[1]; - copyObjectToCell(object, *cell, pos); + Ptr dropped = copyObjectToCell(object, *cell, pos); + PCDropped(dropped); object.getRefData().setCount(0); - + return true; } @@ -1310,8 +1340,8 @@ namespace MWWorld return true; } - void - World::copyObjectToCell(const Ptr &object, CellStore &cell, const ESM::Position &pos) + + Ptr World::copyObjectToCell(const Ptr &object, CellStore &cell, const ESM::Position &pos) { /// \todo add searching correct cell for position specified MWWorld::Ptr dropped = @@ -1335,6 +1365,8 @@ namespace MWWorld } addContainerScripts(dropped, &cell); } + + return dropped; } void World::dropObjectOnGround (const Ptr& actor, const Ptr& object) @@ -1355,7 +1387,9 @@ namespace MWWorld mPhysics->castRay(orig, dir, len); pos.pos[2] = hit.second.z; - copyObjectToCell(object, *cell, pos); + Ptr dropped = copyObjectToCell(object, *cell, pos); + if(actor == mPlayer->getPlayer()) // Only call if dropped by player + PCDropped(dropped); object.getRefData().setCount(0); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index fa5b41038..e8efb6a67 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -91,8 +91,8 @@ namespace MWWorld bool moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return true if the active cell (cell player is in) changed - virtual void - copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos); + + Ptr copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos); void updateWindowManager (); void performUpdateSceneQueries (); @@ -107,6 +107,7 @@ namespace MWWorld void removeContainerScripts(const Ptr& reference); void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell); + void PCDropped (const Ptr& item); public: From 0f58e03343e3d3db1da04398367a5e0704fd7a91 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 31 Jan 2013 19:04:39 +0000 Subject: [PATCH 477/916] Unequipping items will reset OnPCEquip variable --- apps/openmw/mwgui/inventorywindow.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 5390f1602..ebbd69d80 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -7,10 +7,13 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -240,6 +243,29 @@ namespace MWGui if (it != invStore.end() && *it == item) { invStore.equip(slot, invStore.end()); + std::string script = MWWorld::Class::get(*it).getScript(*it); + + /* Unset OnPCEquip Variable on item's script, if it has a script with that variable declared */ + if(script != "") + { + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex("onpcequip"); + char type = locals.getType("onpcequip"); + if(index != -1) + { + switch(type) + { + case 's': + (*it).mRefData->getLocals().mShorts.at (index) = 0; break; + + case 'l': + (*it).mRefData->getLocals().mLongs.at (index) = 0; break; + + case 'f': + (*it).mRefData->getLocals().mFloats.at (index) = 0.0; break; + } + } + } return; } } From 492482de7f98091a90bff0fa4471475ae281dfc4 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Fri, 1 Feb 2013 00:42:03 +0100 Subject: [PATCH 478/916] Add "open" option in opencs. --- apps/opencs/CMakeLists.txt | 4 +-- apps/opencs/view/doc/view.cpp | 29 ++++++++++++++++++- apps/opencs/view/doc/view.hpp | 5 ++++ components/file_order_list/datafileslist.cpp | 16 ++++++++++ components/file_order_list/datafileslist.hpp | 1 + .../file_order_list/model/datafilesmodel.cpp | 20 +++++++++++++ .../file_order_list/model/datafilesmodel.hpp | 1 + 7 files changed, 73 insertions(+), 3 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index abbc953ca..68b22c10e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -17,7 +17,7 @@ set (OPENCS_SRC view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp view/world/dialoguesubview.cpp - view/tools/reportsubview.cpp view/tools/subviews.cpp + view/tools/reportsubview.cpp view/tools/subviews.cpp view/tools/opendialog.cpp ) set (OPENCS_HDR @@ -38,7 +38,7 @@ set (OPENCS_HDR view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp view/world/dialoguesubview.hpp - view/tools/reportsubview.hpp view/tools/subviews.hpp + view/tools/reportsubview.hpp view/tools/subviews.hpp view/tools/opendialog.hpp ) set (OPENCS_US diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 13edb6e74..ebcb9aaa7 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -14,6 +14,8 @@ #include "../tools/subviews.hpp" +#include "../tools/opendialog.hpp" + #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -31,6 +33,10 @@ void CSVDoc::View::setupFileMenu() QAction *new_ = new QAction (tr ("New"), this); connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); file->addAction (new_); + + mLoad = new QAction(tr ("&Load"), this); + connect (mLoad, SIGNAL (triggered()), this, SLOT (load())); + file->addAction (mLoad); mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); @@ -110,7 +116,7 @@ void CSVDoc::View::updateActions() } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) -: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) +: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), mOpenDialog(0) { setDockOptions (QMainWindow::AllowNestedDocks); @@ -205,6 +211,27 @@ void CSVDoc::View::save() mDocument->save(); } +void CSVDoc::View::load() +{ + if (!mOpenDialog) { + mOpenDialog = new OpenDialog(this); + connect(mOpenDialog, SIGNAL(accepted()), this, SLOT(loadNewFiles())); + } + + mOpenDialog->show(); + mOpenDialog->raise(); + mOpenDialog->activateWindow(); +} + +void CSVDoc::View::loadNewFiles() +{ + //FIXME close old files + std::vector paths; + mOpenDialog->getFileList(paths); + //FIXME load new files + +} + void CSVDoc::View::verify() { addSubView (mDocument->verify()); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index b1dedafe9..182252203 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -9,6 +9,7 @@ #include "subviewfactory.hpp" class QAction; +class OpenDialog; namespace CSMDoc { @@ -36,10 +37,12 @@ namespace CSVDoc QAction *mUndo; QAction *mRedo; QAction *mSave; + QAction *mLoad; QAction *mVerify; std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; + OpenDialog * mOpenDialog; // not implemented View (const View&); @@ -92,6 +95,8 @@ namespace CSVDoc void newView(); + void load(); + void loadNewFiles(); void save(); void verify(); diff --git a/components/file_order_list/datafileslist.cpp b/components/file_order_list/datafileslist.cpp index bf4f8cb86..f346407a9 100644 --- a/components/file_order_list/datafileslist.cpp +++ b/components/file_order_list/datafileslist.cpp @@ -451,6 +451,22 @@ bool DataFilesList::setupDataFiles() return true; } +void DataFilesList::getSelectedFiles(std::vector& paths) +{ + QStringList masterPaths = mMastersModel->checkedItemsPaths(); + foreach (const QString &path, masterPaths) + { + paths.push_back(path.toStdString()); + cerr << path.toStdString() << endl; + } + QStringList pluginPaths = mPluginsModel->checkedItemsPaths(); + foreach (const QString &path, pluginPaths) + { + paths.push_back(path.toStdString()); + cerr << path.toStdString() << endl; + } +} + void DataFilesList::writeConfig(QString profile) { // Don't overwrite the config if no masters are found diff --git a/components/file_order_list/datafileslist.hpp b/components/file_order_list/datafileslist.hpp index 7bb6605ab..7bdb5e057 100644 --- a/components/file_order_list/datafileslist.hpp +++ b/components/file_order_list/datafileslist.hpp @@ -32,6 +32,7 @@ public: void writeConfig(QString profile = QString()); bool showDataFilesWarning(); bool setupDataFiles(); + void getSelectedFiles(std::vector& paths); public slots: void setCheckState(QModelIndex index); diff --git a/components/file_order_list/model/datafilesmodel.cpp b/components/file_order_list/model/datafilesmodel.cpp index e84dbe0ac..5bb199679 100644 --- a/components/file_order_list/model/datafilesmodel.cpp +++ b/components/file_order_list/model/datafilesmodel.cpp @@ -292,6 +292,7 @@ void DataFilesModel::addMasters(const QString &path) EsmFile *file = new EsmFile(master); file->setDates(info.lastModified(), info.lastRead()); + file->setPath(info.absoluteFilePath()); // Add the master to the table if (findItem(master) == 0) @@ -427,6 +428,25 @@ QStringList DataFilesModel::checkedItems() return list; } +QStringList DataFilesModel::checkedItemsPaths() +{ + QStringList list; + + QList::ConstIterator it; + QList::ConstIterator itEnd = mFiles.constEnd(); + + int i = 0; + for (it = mFiles.constBegin(); it != itEnd; ++it) { + EsmFile *file = item(i); + ++i; + + if (mCheckStates[file->fileName()] == Qt::Checked && mAvailableFiles.contains(file->fileName())) + list << file->path(); + } + + return list; +} + void DataFilesModel::uncheckAll() { emit layoutAboutToBeChanged(); diff --git a/components/file_order_list/model/datafilesmodel.hpp b/components/file_order_list/model/datafilesmodel.hpp index 29a770a86..adc80eac2 100644 --- a/components/file_order_list/model/datafilesmodel.hpp +++ b/components/file_order_list/model/datafilesmodel.hpp @@ -43,6 +43,7 @@ public: QStringList checkedItems(); QStringList uncheckedItems(); + QStringList checkedItemsPaths(); Qt::CheckState checkState(const QModelIndex &index); void setCheckState(const QModelIndex &index, Qt::CheckState state); From 376dfed15ba01cee8d24d122dfafc797a86fd303 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Feb 2013 08:50:32 -0800 Subject: [PATCH 479/916] Revert "Use a child scene node for the accumulation root" This reverts commit d6f923f2743afd4bd781e5a31bc5f897f3f18785. We don't need it for any of the NIFs we're currently handling. As long as there's no NIF files that would break it, we should require a stationary root if an animation wants to accumulate. If we must, a better idea may be to inject an extra bone into the skeleton instance and make that the accumulation root. --- apps/openmw/mwrender/animation.cpp | 5 +++-- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b81104067..b63de2f16 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node->createChildSceneNode(); + mInsert = node; assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,7 +76,8 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = mInsert; + mAccumRoot = skelinst->getRootBone(); + mAccumRoot->setManuallyControlled(true); mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 165a6525c..60e524d28 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Node *mAccumRoot; + Ogre::Bone *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From a461b282c15083e6987356a1643c7b8a5b4295a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Feb 2013 23:43:23 +0100 Subject: [PATCH 480/916] water ripples (experimental) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 +- apps/openmw/mwrender/ripplesimulation.cpp | 212 ++++++++++++++++++ apps/openmw/mwrender/ripplesimulation.hpp | 72 ++++++ apps/openmw/mwrender/water.cpp | 14 +- apps/openmw/mwrender/water.hpp | 5 +- extern/shiny/Main/Factory.cpp | 2 + files/CMakeLists.txt | 7 + files/materials/core.h | 4 + files/materials/quad.mat | 2 +- files/materials/quad.shaderset | 2 +- files/materials/water.mat | 8 +- files/materials/water.shader | 28 ++- files/materials/watersim.mat | 59 +++++ files/materials/watersim.shaderset | 31 +++ files/materials/watersim_addimpulse.shader | 12 + files/materials/watersim_common.h | 25 +++ files/materials/watersim_heightmap.shader | 42 ++++ .../materials/watersim_heighttonormal.shader | 27 +++ files/water/circle.png | Bin 0 -> 753 bytes 20 files changed, 545 insertions(+), 14 deletions(-) create mode 100644 apps/openmw/mwrender/ripplesimulation.cpp create mode 100644 apps/openmw/mwrender/ripplesimulation.hpp create mode 100644 files/materials/watersim.mat create mode 100644 files/materials/watersim.shaderset create mode 100644 files/materials/watersim_addimpulse.shader create mode 100644 files/materials/watersim_common.h create mode 100644 files/materials/watersim_heightmap.shader create mode 100644 files/materials/watersim_heighttonormal.shader create mode 100644 files/water/circle.png diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090..2c49e848e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows - compositors characterpreview externalrendering globalmap videoplayer + compositors characterpreview externalrendering globalmap videoplayer ripplesimulation ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ff26b087c..3fed4d994 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -386,7 +386,10 @@ void RenderingManager::update (float duration, bool paused) *world->getPlayer().getPlayer().getCell()->mCell, Ogre::Vector3(cam.x, -cam.z, cam.y)) ); - mWater->update(duration); + + // MW to ogre coordinates + orig = Ogre::Vector3(orig.x, orig.z, -orig.y); + mWater->update(duration, orig); } } diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp new file mode 100644 index 000000000..6096c7ba3 --- /dev/null +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -0,0 +1,212 @@ +#include "ripplesimulation.hpp" + +#include +#include +#include +#include + +#include + +namespace MWRender +{ + + +RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) + : mMainSceneMgr(mainSceneManager), + mTime(0), + mCurrentFrameOffset(0,0), + mPreviousFrameOffset(0,0), + mRippleCenter(0,0), + mTextureSize(512), + mRippleAreaLength(1000), + mImpulseSize(20), + mTexelOffset(0,0) +{ + Ogre::AxisAlignedBox aabInf; + aabInf.setInfinite(); + + + mHeightToNormalMapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightToNormalMap"); + mHeightmapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightmapSimulation"); + + mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); + + mCamera = mSceneMgr->createCamera("RippleCamera"); + + mRectangle = new Ogre::Rectangle2D(true); + mRectangle->setBoundingBox(aabInf); + mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0, false); + Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + node->attachObject(mRectangle); + + mImpulse = new Ogre::Rectangle2D(true); + mImpulse->setCorners(-0.1, 0.1, 0.1, -0.1, false); + mImpulse->setBoundingBox(aabInf); + mImpulse->setMaterial("AddImpulse"); + Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + impulseNode->attachObject(mImpulse); + + float w=0.05; + for (int i=0; i<4; ++i) + { + Ogre::TexturePtr texture; + if (i != 3) + texture = Ogre::TextureManager::getSingleton().createManual("RippleHeight" + Ogre::StringConverter::toString(i), + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); + else + texture = Ogre::TextureManager::getSingleton().createManual("RippleNormal", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); + + + Ogre::RenderTexture* rt = texture->getBuffer()->getRenderTarget(); + rt->removeAllViewports(); + rt->addViewport(mCamera); + rt->setAutoUpdated(false); + rt->getViewport(0)->setClearEveryFrame(false); + + // debug overlay + Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true); + debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false); + w += 0.2; + debugOverlay->setBoundingBox(aabInf); + + Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode(); + debugNode->attachObject(debugOverlay); + + Ogre::MaterialPtr debugMaterial = Ogre::MaterialManager::getSingleton().create("RippleDebug" + Ogre::StringConverter::toString(i), + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + + if (i != 3) + debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleHeight" + Ogre::StringConverter::toString(i)); + else + debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleNormal"); + debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + + debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i)); + + mRenderTargets[i] = rt; + mTextures[i] = texture; + } + + sh::Factory::getInstance().setSharedParameter("rippleTextureSize", sh::makeProperty( + new sh::Vector4(1.0/512, 1.0/512, 512, 512))); + sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( + new sh::Vector3(0, 0, 0))); + sh::Factory::getInstance().setSharedParameter("rippleAreaLength", sh::makeProperty( + new sh::FloatValue(mRippleAreaLength))); + +} + +RippleSimulation::~RippleSimulation() +{ + delete mRectangle; + + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); +} + +void RippleSimulation::update(float dt, Ogre::Vector2 position) +{ + // try to keep 20 fps + mTime += dt; + + while (mTime >= 1/20.0) + { + mPreviousFrameOffset = mCurrentFrameOffset; + + mCurrentFrameOffset = position - mRippleCenter; + // add texel offsets from previous frame. + mCurrentFrameOffset += mTexelOffset; + + mTexelOffset = Ogre::Vector2(std::fmod(mCurrentFrameOffset.x, 1.0f/mTextureSize), + std::fmod(mCurrentFrameOffset.y, 1.0f/mTextureSize)); + + // now subtract new offset in order to snap to texels + mCurrentFrameOffset -= mTexelOffset; + + // texture coordinate space + mCurrentFrameOffset /= mRippleAreaLength; + + std::cout << "Offset " << mCurrentFrameOffset << std::endl; + + mRippleCenter = position; + + addImpulses(); + waterSimulation(); + heightMapToNormalMap(); + + swapHeightMaps(); + mTime -= 1/20.0; + } + + sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( + new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); +} + +void RippleSimulation::addImpulse(Ogre::Vector2 position) +{ + mImpulses.push(position); +} + +void RippleSimulation::addImpulses() +{ + mRectangle->setVisible(false); + mImpulse->setVisible(true); + + while (mImpulses.size()) + { + Ogre::Vector2 pos = mImpulses.front(); + pos -= mRippleCenter; + pos /= mRippleAreaLength; + float size = mImpulseSize / mRippleAreaLength; + mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); + mImpulses.pop(); + + mRenderTargets[1]->update(); + } + + mImpulse->setVisible(false); + mRectangle->setVisible(true); +} + +void RippleSimulation::waterSimulation() +{ + mRectangle->setMaterial("HeightmapSimulation"); + + sh::Factory::getInstance().setTextureAlias("Heightmap0", mTextures[0]->getName()); + sh::Factory::getInstance().setTextureAlias("Heightmap1", mTextures[1]->getName()); + + sh::Factory::getInstance().setSharedParameter("currentFrameOffset", sh::makeProperty( + new sh::Vector3(mCurrentFrameOffset.x, mCurrentFrameOffset.y, 0))); + sh::Factory::getInstance().setSharedParameter("previousFrameOffset", sh::makeProperty( + new sh::Vector3(mPreviousFrameOffset.x, mPreviousFrameOffset.y, 0))); + + mRenderTargets[2]->update(); +} + +void RippleSimulation::heightMapToNormalMap() +{ + mRectangle->setMaterial("HeightToNormalMap"); + + sh::Factory::getInstance().setTextureAlias("Heightmap2", mTextures[2]->getName()); + + mRenderTargets[TEX_NORMAL]->update(); +} + +void RippleSimulation::swapHeightMaps() +{ + // 0 -> 1 -> 2 to 2 -> 0 ->1 + Ogre::RenderTexture* tmp = mRenderTargets[0]; + Ogre::TexturePtr tmp2 = mTextures[0]; + + mRenderTargets[0] = mRenderTargets[1]; + mTextures[0] = mTextures[1]; + + mRenderTargets[1] = mRenderTargets[2]; + mTextures[1] = mTextures[2]; + + mRenderTargets[2] = tmp; + mTextures[2] = tmp2; +} + + +} diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp new file mode 100644 index 000000000..6096fa866 --- /dev/null +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -0,0 +1,72 @@ +#ifndef RIPPLE_SIMULATION_H +#define RIPPLE_SIMULATION_H + +#include +#include +#include + +namespace Ogre +{ + class RenderTexture; + class Camera; + class SceneManager; + class Rectangle2D; +} + +namespace MWRender +{ + +class RippleSimulation +{ +public: + RippleSimulation(Ogre::SceneManager* mainSceneManager); + ~RippleSimulation(); + + void update(float dt, Ogre::Vector2 position); + + void addImpulse (Ogre::Vector2 position); + +private: + Ogre::RenderTexture* mRenderTargets[4]; + Ogre::TexturePtr mTextures[4]; + + int mTextureSize; + float mRippleAreaLength; + float mImpulseSize; + + Ogre::Camera* mCamera; + + // own scenemanager to render our simulation + Ogre::SceneManager* mSceneMgr; + Ogre::Rectangle2D* mRectangle; + + // scenemanager to create the debug overlays on + Ogre::SceneManager* mMainSceneMgr; + + Ogre::MaterialPtr mHeightmapMaterial; + Ogre::MaterialPtr mHeightToNormalMapMaterial; + + static const int TEX_NORMAL = 3; + + Ogre::Rectangle2D* mImpulse; + + std::queue mImpulses; + + void addImpulses(); + void heightMapToNormalMap(); + void waterSimulation(); + void swapHeightMaps(); + + float mTime; + + Ogre::Vector2 mRippleCenter; + + Ogre::Vector2 mTexelOffset; + + Ogre::Vector2 mCurrentFrameOffset; + Ogre::Vector2 mPreviousFrameOffset; +}; + +} + +#endif diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 27b9fc679..6ee3890dd 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -12,6 +12,7 @@ #include "sky.hpp" #include "renderingmanager.hpp" #include "compositors.hpp" +#include "ripplesimulation.hpp" #include #include @@ -180,8 +181,11 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mActive(1), mToggled(1), mRendering(rend), mWaterTimer(0.f), - mReflection(NULL) + mReflection(NULL), + mSimulation(NULL) { + mSimulation = new RippleSimulation(mSceneMgr); + mSky = rend->getSkyManager(); mMaterial = MaterialManager::getSingleton().getByName("Water"); @@ -375,7 +379,7 @@ void Water::updateVisible() } } -void Water::update(float dt) +void Water::update(float dt, Ogre::Vector3 player) { /* Ogre::Vector3 pos = mCamera->getDerivedPosition (); @@ -387,6 +391,12 @@ void Water::update(float dt) sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); + + //if (player.y <= mTop) + { + mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); + } + mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); } void Water::applyRTT() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index de78542b7..97eb590b3 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -29,6 +29,7 @@ namespace MWRender { class SkyManager; class RenderingManager; + class RippleSimulation; class Reflection { @@ -110,6 +111,8 @@ namespace MWRender { float mWaterTimer; + RippleSimulation* mSimulation; + Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); protected: @@ -137,7 +140,7 @@ namespace MWRender { void setActive(bool active); void toggle(); - void update(float dt); + void update(float dt, Ogre::Vector3 player); void assignTextures(); diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 82d664811..6e87800e5 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -219,6 +219,8 @@ namespace sh break; } + std::cout << "loading " << it->first << std::endl; + MaterialInstance newInstance(it->first, this); newInstance.create(mPlatform); if (!mShadersEnabled) diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index e8426afb7..65ebc31a2 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -3,6 +3,7 @@ project(resources) set(WATER_FILES underwater_dome.mesh water_nm.png + circle.png ) set(GBUFFER_FILES @@ -43,6 +44,12 @@ set(MATERIAL_FILES selection.mat selection.shader selection.shaderset + watersim_heightmap.shader + watersim_addimpulse.shader + watersim_heighttonormal.shader + watersim_common.h + watersim.mat + watersim.shaderset ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/core.h b/files/materials/core.h index 0e46369ef..e498a3809 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -28,6 +28,8 @@ #define shNormalInput(type) , in type normal : NORMAL #define shColourInput(type) , in type colour : COLOR + + #define shFract(val) frac(val) #ifdef SH_VERTEX_SHADER @@ -64,6 +66,8 @@ #if SH_GLSL == 1 + #define shFract(val) fract(val) + @version 120 #define float2 vec2 diff --git a/files/materials/quad.mat b/files/materials/quad.mat index afb7f5111..a484d7f28 100644 --- a/files/materials/quad.mat +++ b/files/materials/quad.mat @@ -4,7 +4,7 @@ material quad pass { - vertex_program quad_vertex + vertex_program transform_vertex fragment_program quad_fragment depth_write $depth_write diff --git a/files/materials/quad.shaderset b/files/materials/quad.shaderset index c61497503..ee230a303 100644 --- a/files/materials/quad.shaderset +++ b/files/materials/quad.shaderset @@ -1,4 +1,4 @@ -shader_set quad_vertex +shader_set transform_vertex { source quad.shader type vertex diff --git a/files/materials/water.mat b/files/materials/water.mat index a5f9f2ec9..c427447d2 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -34,7 +34,13 @@ material Water { direct_texture water_nm.png } - + + texture_unit rippleNormalMap + { + direct_texture RippleNormal + tex_address_mode border + tex_border_colour 0.5 0.5 1.0 + } // for simple_water texture_unit animatedTexture diff --git a/files/materials/water.shader b/files/materials/water.shader index 9ebea0f00..1e14dd596 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -61,7 +61,7 @@ // Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) - +#define RIPPLES 1 #ifdef SH_VERTEX_SHADER @@ -119,8 +119,8 @@ #define WAVE_SCALE 75 // overall wave scale #define BUMP 1.5 // overall water surface bumpiness - #define REFL_BUMP 0.08 // reflection distortion amount - #define REFR_BUMP 0.06 // refraction distortion amount + #define REFL_BUMP 0.16 // reflection distortion amount + #define REFR_BUMP 0.12 // refraction distortion amount #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering @@ -159,6 +159,11 @@ shInput(float3, screenCoordsPassthrough) shInput(float4, position) shInput(float, depthPassthrough) + + #if RIPPLES + shUniform(float3, rippleCenter) @shSharedParameter(rippleCenter, rippleCenter) + shUniform(float, rippleAreaLength) @shSharedParameter(rippleAreaLength, rippleAreaLength) + #endif shUniform(float, far) @shAutoConstant(far, far_clip_distance) @@ -166,6 +171,11 @@ shSampler2D(refractionMap) shSampler2D(depthMap) shSampler2D(normalMap) + + #if RIPPLES + shSampler2D(rippleNormalMap) + shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) + #endif shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #define WIND_SPEED windDir_windSpeed.z @@ -220,8 +230,14 @@ float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xzy; - - normal = normalize(float3(normal.x * BUMP, normal.y, normal.z * BUMP)); + + float4 worldPosition = shMatrixMult(wMat, float4(position.xyz, 1)); + float2 relPos = (worldPosition.xz - rippleCenter.xy) / rippleAreaLength + 0.5; + float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2 - 1); + normal_ripple = normal_ripple.xzy; + + normal = normalize(normal + normal_ripple); + // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + @@ -303,7 +319,7 @@ } shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); - + //shOutputColour(0).xyz = float3(relPos.x, relPos.y, 0); shOutputColour(0).w = 1; } diff --git a/files/materials/watersim.mat b/files/materials/watersim.mat new file mode 100644 index 000000000..b58b1a851 --- /dev/null +++ b/files/materials/watersim.mat @@ -0,0 +1,59 @@ +material HeightmapSimulation +{ + allow_fixed_function false + pass + { + depth_check off + depth_write off + vertex_program transform_vertex + fragment_program watersim_fragment + + texture_unit heightPrevSampler + { + tex_address_mode border + tex_border_colour 0 0 0 + texture_alias Heightmap0 + } + texture_unit heightCurrentSampler + { + tex_address_mode border + tex_border_colour 0 0 0 + texture_alias Heightmap1 + } + } +} + +material HeightToNormalMap +{ + allow_fixed_function false + pass + { + depth_check off + depth_write off + vertex_program transform_vertex + fragment_program height_to_normal_fragment + + texture_unit heightCurrentSampler + { + texture_alias Heightmap2 + } + } +} + +material AddImpulse +{ + allow_fixed_function false + pass + { + depth_check off + depth_write off + scene_blend alpha_blend + vertex_program transform_vertex + fragment_program add_impulse_fragment + + texture_unit alphaMap + { + texture circle.png + } + } +} diff --git a/files/materials/watersim.shaderset b/files/materials/watersim.shaderset new file mode 100644 index 000000000..ea512e25f --- /dev/null +++ b/files/materials/watersim.shaderset @@ -0,0 +1,31 @@ +shader_set transform_vertex +{ + source quad.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set watersim_fragment +{ + source watersim_heightmap.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} + +shader_set height_to_normal_fragment +{ + source watersim_heighttonormal.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} + +shader_set add_impulse_fragment +{ + source watersim_addimpulse.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} diff --git a/files/materials/watersim_addimpulse.shader b/files/materials/watersim_addimpulse.shader new file mode 100644 index 000000000..3ca4192cd --- /dev/null +++ b/files/materials/watersim_addimpulse.shader @@ -0,0 +1,12 @@ +#include "core.h" +#include "watersim_common.h" + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shSampler2D(alphaMap) + + SH_START_PROGRAM + { + shOutputColour(0) = EncodeHeightmap(1.0); + shOutputColour(0).a = shSample (alphaMap, UV.xy).a; + } diff --git a/files/materials/watersim_common.h b/files/materials/watersim_common.h new file mode 100644 index 000000000..aa7a636a0 --- /dev/null +++ b/files/materials/watersim_common.h @@ -0,0 +1,25 @@ +float DecodeHeightmap(float4 heightmap) +{ + float4 table = float4(1.0, -1.0, 0.0, 0.0); + return dot(heightmap, table); +} + +float DecodeHeightmap(shTexture2D HeightmapSampler, float2 texcoord) +{ + float4 heightmap = shSample(HeightmapSampler, texcoord); + return DecodeHeightmap(heightmap); +} + +float4 EncodeHeightmap(float fHeight) +{ + float h = fHeight; + float positive = fHeight > 0.0 ? fHeight : 0.0; + float negative = fHeight < 0.0 ? -fHeight : 0.0; + + float4 color = float4(0,0,0,0); + + color.r = positive; + color.g = negative; + + return color; +} diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader new file mode 100644 index 000000000..e19270d39 --- /dev/null +++ b/files/materials/watersim_heightmap.shader @@ -0,0 +1,42 @@ +#include "core.h" + +#define DAMPING 0.92 + +#include "watersim_common.h" + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shSampler2D(heightPrevSampler) + shSampler2D(heightCurrentSampler) + shUniform(float3, previousFrameOffset) @shSharedParameter(previousFrameOffset, previousFrameOffset) + shUniform(float3, currentFrameOffset) @shSharedParameter(currentFrameOffset, currentFrameOffset) + shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) + + SH_START_PROGRAM + { + const float3 offset[4] = float3[4]( + float3(-1.0, 0.0, 0.25), + float3( 1.0, 0.0, 0.25), + float3( 0.0,-1.0, 0.25), + float3( 0.0, 1.0, 0.25) + ); + + float fHeightPrev = DecodeHeightmap(heightPrevSampler, UV.xy + previousFrameOffset.xy + currentFrameOffset.xy); + + float fNeighCurrent = 0; + for ( int i=0; i<4; i++ ) + { + float2 vTexcoord = UV + currentFrameOffset.xy + offset[i].xy * rippleTextureSize.xy; + fNeighCurrent += (DecodeHeightmap(heightCurrentSampler, vTexcoord) * offset[i].z); + } + + float fHeight = fNeighCurrent * 2.0 - fHeightPrev; + + fHeight *= DAMPING; + + shOutputColour(0) = EncodeHeightmap(fHeight); + } + + + + diff --git a/files/materials/watersim_heighttonormal.shader b/files/materials/watersim_heighttonormal.shader new file mode 100644 index 000000000..5402b6bb5 --- /dev/null +++ b/files/materials/watersim_heighttonormal.shader @@ -0,0 +1,27 @@ +#include "core.h" +#include "watersim_common.h" + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shSampler2D(heightCurrentSampler) + shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) + + SH_START_PROGRAM + { + float2 offset[4] = float2[4] ( + vec2(-1.0, 0.0), + vec2( 1.0, 0.0), + vec2( 0.0,-1.0), + vec2( 0.0, 1.0) + ); + + float fHeightL = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[0]*rippleTextureSize.xy); + float fHeightR = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[1]*rippleTextureSize.xy); + float fHeightT = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[2]*rippleTextureSize.xy); + float fHeightB = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[3]*rippleTextureSize.xy); + + float3 n = float3(fHeightB - fHeightT, fHeightR - fHeightL, 1.0); + float3 normal = (n + 1.0) * 0.5; + + shOutputColour(0) = float4(normal.rgb, 1.0); + } diff --git a/files/water/circle.png b/files/water/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1cf268c0be2cdae27fe04ee7f7c0aa6de12c11 GIT binary patch literal 753 zcmVPx#32;bRa{vGf6951U69E94oEQKA00(qQO+^RY0s#yODLP_H6#xJL8FWQhbVF}# zZDnqB07G(RVRU6=Aa`kWXdp*PO;A^X4i^9b0$xc(K~#9!?VG<&8$l4pf3r}yK~51x zqM)L&3(GXPrAgYOr>3Lk4JgeU@D%ooAf>PicNCFA3Q(Fz0Zj_eDdq^q=iI@0XFq8g z%YXL!d^@wd^R1{VbwWh8fL)*q99VRLJ>Vno0NepLzy!Fqm;m2Y^|96gs%qr{w1Es5 z0s5aYvhQlwGS&)73oxjN^fEC9fHXz`BmM=rt&w;!ZtXYaT?GL8!0Zi)7h?wW-&_Eo z1q|Pjcrk`RYaK39whD+y2lxtX(=0pyJyo5S`A{fHKC|-FH1gP(CN{?E%OG&pphy0- zIIA=V0OuP-K9BQC1lX{DzVwsu8u@I4$>))+B>>QgfP5aEQe{v?TENeSX8UzZkrykKL0jHxq|slR18ie6i&%hJaRXJH0-u3>;>Esk{G0FcBq$;Re794Y znDGPnq(*%42{?2>9^-iUED6?plGC&pJy{2cNZSr3J>i3@-se-`2!A+Q%mJqk1vt&? z{+2BjJz_gp)50rugLP@Vq8qGLfHVc>U0Sc$6X17bhaaU*iUQ6N9PR-YaTl07 zGrZy^Fz@ww#UwEI<9Nk&62SWuNZVoa;f)=VAFJwPz7V={D8Lnv4n+fis@^-B24my= zq%SbQPhVj0%pc&sHD)iIIC%U|bkP;!y*-``5-%8}h7pn{vCMkPkFQUZP`xp5a z1uzk&z;OiRkC!^glT|jErITI0j0l@xp3c&hnGz`78L}VP0WKRv{?h9Flr;#YYjf%1 jWV$-*_wuxOzdrv5<*cfu_Ri)S00000NkvXXu0mjfBzZwt literal 0 HcmV?d00001 From 4e46f403a9710ed3cda61b6615e3c0c7bdf992d8 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 28 Jan 2013 22:07:39 -0800 Subject: [PATCH 481/916] added some more warning to ignore in MSVC --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2313d2d95..9c4ce5cd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -496,7 +496,7 @@ if (WIN32) # Warnings that aren't enabled normally and don't need to be enabled # They're unneeded and sometimes completely retarded warnings that /Wall enables # Not going to bother commenting them as they tend to warn on every standard library files - 4061 4263 4264 4266 4350 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 + 4061 4263 4264 4266 4350 4371 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 # Warnings that are thrown on standard libraries and not OpenMW 4347 # Non-template function with same name and parameter count as template function @@ -506,6 +506,11 @@ if (WIN32) 4738 # Storing 32-bit float result in memory, possible loss of performance 4986 # Undocumented warning that occurs in the crtdbg.h file 4996 # Function was declared deprecated + + # 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' # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type From 7f87c1873b4fbd4b27590d1313f8a15bd1ba55cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 02:53:22 -0800 Subject: [PATCH 482/916] Use an array to store the entity parts --- apps/openmw/mwrender/npcanimation.cpp | 62 +++++++++++++-------------- apps/openmw/mwrender/npcanimation.hpp | 31 +------------- 2 files changed, 33 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 03fda8982..18f44c87c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -16,39 +16,39 @@ namespace MWRender { const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize] = { - { ESM::PRT_Head, &NpcAnimation::mHead, "Head" }, - { ESM::PRT_Hair, &NpcAnimation::mHair, "Head" }, - { ESM::PRT_Neck, &NpcAnimation::mNeck, "Neck" }, - { ESM::PRT_Cuirass, &NpcAnimation::mChest, "Chest" }, - { ESM::PRT_Groin, &NpcAnimation::mGroin, "Groin" }, - { ESM::PRT_Skirt, &NpcAnimation::mSkirt, "Groin" }, - { ESM::PRT_RHand, &NpcAnimation::mHandR, "Right Hand" }, - { ESM::PRT_LHand, &NpcAnimation::mHandL, "Left Hand" }, - { ESM::PRT_RWrist, &NpcAnimation::mWristR, "Right Wrist" }, - { ESM::PRT_LWrist, &NpcAnimation::mWristL, "Left Wrist" }, - { ESM::PRT_Shield, &NpcAnimation::mShield, "Shield" }, - { ESM::PRT_RForearm, &NpcAnimation::mForearmR, "Right Forearm" }, - { ESM::PRT_LForearm, &NpcAnimation::mForearmL, "Left Forearm" }, - { ESM::PRT_RUpperarm, &NpcAnimation::mUpperArmR, "Right Upper Arm" }, - { ESM::PRT_LUpperarm, &NpcAnimation::mUpperArmL, "Left Upper Arm" }, - { ESM::PRT_RFoot, &NpcAnimation::mFootR, "Right Foot" }, - { ESM::PRT_LFoot, &NpcAnimation::mFootL, "Left Foot" }, - { ESM::PRT_RAnkle, &NpcAnimation::mAnkleR, "Right Ankle" }, - { ESM::PRT_LAnkle, &NpcAnimation::mAnkleL, "Left Ankle" }, - { ESM::PRT_RKnee, &NpcAnimation::mKneeR, "Right Knee" }, - { ESM::PRT_LKnee, &NpcAnimation::mKneeL, "Left Knee" }, - { ESM::PRT_RLeg, &NpcAnimation::mUpperLegR, "Right Upper Leg" }, - { ESM::PRT_LLeg, &NpcAnimation::mUpperLegL, "Left Upper Leg" }, - { ESM::PRT_RPauldron, &NpcAnimation::mClavicleR, "Right Clavicle" }, - { ESM::PRT_LPauldron, &NpcAnimation::mClavicleL, "Left Clavicle" }, - { ESM::PRT_Weapon, &NpcAnimation::mWeapon, "Weapon" }, - { ESM::PRT_Tail, &NpcAnimation::mTail, "Tail" } + { ESM::PRT_Head, "Head" }, + { ESM::PRT_Hair, "Head" }, + { ESM::PRT_Neck, "Neck" }, + { ESM::PRT_Cuirass, "Chest" }, + { ESM::PRT_Groin, "Groin" }, + { ESM::PRT_Skirt, "Groin" }, + { ESM::PRT_RHand, "Right Hand" }, + { ESM::PRT_LHand, "Left Hand" }, + { ESM::PRT_RWrist, "Right Wrist" }, + { ESM::PRT_LWrist, "Left Wrist" }, + { ESM::PRT_Shield, "Shield" }, + { ESM::PRT_RForearm, "Right Forearm" }, + { ESM::PRT_LForearm, "Left Forearm" }, + { ESM::PRT_RUpperarm, "Right Upper Arm" }, + { ESM::PRT_LUpperarm, "Left Upper Arm" }, + { ESM::PRT_RFoot, "Right Foot" }, + { ESM::PRT_LFoot, "Left Foot" }, + { ESM::PRT_RAnkle, "Right Ankle" }, + { ESM::PRT_LAnkle, "Left Ankle" }, + { ESM::PRT_RKnee, "Right Knee" }, + { ESM::PRT_LKnee, "Left Knee" }, + { ESM::PRT_RLeg, "Right Upper Leg" }, + { ESM::PRT_LLeg, "Left Upper Leg" }, + { ESM::PRT_RPauldron, "Right Clavicle" }, + { ESM::PRT_LPauldron, "Left Clavicle" }, + { ESM::PRT_Weapon, "Weapon" }, + { ESM::PRT_Tail, "Tail" } }; NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - removeEntities(this->*sPartList[i].ents); + removeEntities(mEntityParts[i]); } @@ -336,7 +336,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { - Ogre::Entity *ent = (this->*sPartList[i].ents).mSkelBase; + Ogre::Entity *ent = mEntityParts[i].mSkelBase; if(!ent) continue; updateSkeletonInstance(skelsrc, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); @@ -367,7 +367,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeEntities(this->*sPartList[i].ents); + removeEntities(mEntityParts[i]); break; } } @@ -405,7 +405,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - this->*sPartList[i].ents = insertBoundedPart(mesh, group, sPartList[i].name); + mEntityParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index a4e87e722..513741d03 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -19,7 +19,6 @@ class NpcAnimation : public Animation public: struct PartInfo { ESM::PartReferenceType type; - NifOgre::EntityList NpcAnimation::*ents; const char name[32]; }; @@ -30,34 +29,8 @@ private: MWWorld::InventoryStore& mInv; int mStateID; - //Bounded Parts - NifOgre::EntityList mClavicleL; - NifOgre::EntityList mClavicleR; - NifOgre::EntityList mUpperArmL; - NifOgre::EntityList mUpperArmR; - NifOgre::EntityList mUpperLegL; - NifOgre::EntityList mUpperLegR; - NifOgre::EntityList mForearmL; - NifOgre::EntityList mForearmR; - NifOgre::EntityList mWristL; - NifOgre::EntityList mWristR; - NifOgre::EntityList mKneeR; - NifOgre::EntityList mKneeL; - NifOgre::EntityList mNeck; - NifOgre::EntityList mAnkleL; - NifOgre::EntityList mAnkleR; - NifOgre::EntityList mGroin; - NifOgre::EntityList mSkirt; - NifOgre::EntityList mFootL; - NifOgre::EntityList mFootR; - NifOgre::EntityList mHair; - NifOgre::EntityList mHandL; - NifOgre::EntityList mHandR; - NifOgre::EntityList mShield; - NifOgre::EntityList mWeapon; - NifOgre::EntityList mHead; - NifOgre::EntityList mChest; - NifOgre::EntityList mTail; + // Bounded Parts + NifOgre::EntityList mEntityParts[sPartListSize]; const ESM::NPC *mNpc; std::string mHeadModel; From 85697e4628d3cd983f7b706dc890da97e0634027 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Feb 2013 13:24:28 +0100 Subject: [PATCH 483/916] reverted to C++03 --- CMakeLists.txt | 4 ++-- apps/openmw/mwworld/actionequip.cpp | 12 ++++++------ components/bsa/bsa_archive.cpp | 2 +- components/files/constrainedfiledatastream.cpp | 9 +++------ 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c4ce5cd8..c944730ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,7 +306,7 @@ endif() # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++0x -pedantic) + add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++03 -pedantic -Wno-long-long) # Silence warnings in OGRE headers. Remove once OGRE got fixed! add_definitions (-Wno-ignored-qualifiers) @@ -506,7 +506,7 @@ if (WIN32) 4738 # Storing 32-bit float result in memory, possible loss of performance 4986 # Undocumented warning that occurs in the crtdbg.h file 4996 # Function was declared deprecated - + # 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' diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 60260a812..f3191e8bb 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -32,7 +32,7 @@ namespace MWWorld } assert(it != invStore.end()); - + std::string npcRace = actor.get()->mBase->mRace; // equip the item in the first free slot @@ -43,7 +43,7 @@ namespace MWWorld // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) if(npcRace == "argonian" || npcRace == "khajiit") { - if(*slot == MWWorld::InventoryStore::Slot_Helmet){ + if(*slot == MWWorld::InventoryStore::Slot_Helmet){ std::vector parts; if(it.getType() == MWWorld::ContainerStore::Type_Clothing) @@ -54,22 +54,22 @@ namespace MWWorld bool allow = true; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { - if((*itr).mPart == ESM::PartReferenceType::PRT_Head) + if((*itr).mPart == ESM::PRT_Head) { if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector()); - + allow = false; break; } } - + if(!allow) break; } if (*slot == MWWorld::InventoryStore::Slot_Boots) - { + { // Only notify the player, not npcs if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) { diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 5274564a6..8117dbdfd 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -91,7 +91,7 @@ public: std::string searchable = normalize_path (proper.begin () + prefix, proper.end ()); - mIndex.insert (std::make_pair (std::move (searchable), std::move (proper))); + mIndex.insert (std::make_pair (searchable, proper)); } } diff --git a/components/files/constrainedfiledatastream.cpp b/components/files/constrainedfiledatastream.cpp index dd2985e56..321bcf7c8 100644 --- a/components/files/constrainedfiledatastream.cpp +++ b/components/files/constrainedfiledatastream.cpp @@ -3,11 +3,8 @@ #include #include -#ifndef __clang__ -#include -#else -#include -#endif + +#include namespace { @@ -29,7 +26,7 @@ public: mBufferOrigin = 0; mBufferExtent = 0; } - + size_t read(void* buf, size_t count) { From 827261e8b4c4fb2761429fa79c1c88721ae1602e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Feb 2013 13:42:11 +0100 Subject: [PATCH 484/916] increased version number --- CMakeLists.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c944730ab..165db6b79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 20) +set (OPENMW_VERSION_MINOR 21) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") diff --git a/readme.txt b/readme.txt index 21ae85530..d94ccd7f0 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.20.0 +Version: 0.21.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From e6e7c69013070bd1c76f13a5d98739a9fc850fdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 05:26:52 -0800 Subject: [PATCH 485/916] Fix handling of filtered entities --- components/nifogre/ogre_nif_loader.cpp | 33 +++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9c9fd3b22..2da8033e6 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -1212,16 +1213,8 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); - if(ent->hasSkeleton()) - { - if(meshes[i].mMeshName.find(filter) == std::string::npos) - { - sceneMgr->destroyEntity(ent); - continue; - } - if(!entitylist.mSkelBase) - entitylist.mSkelBase = ent; - } + if(!entitylist.mSkelBase && ent->hasSkeleton()) + entitylist.mSkelBase = ent; entitylist.mEntities.push_back(ent); } @@ -1231,19 +1224,25 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(entitylist.mSkelBase) { - parentNode->attachObject(entitylist.mSkelBase); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; - if(entity != entitylist.mSkelBase && entity->hasSkeleton()) + if(entity->hasSkeleton()) { - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - parentNode->attachObject(entity); + if(entity != entitylist.mSkelBase) + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); + if(entity->getMesh()->getName().find(filter) != std::string::npos) + parentNode->attachObject(entity); } - else if(entity != entitylist.mSkelBase) + else { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(bonename, entity); - tag->setScale(scale); + if(entity->getMesh()->getName().find(filter) != std::string::npos) + { + Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + tag->setPosition(meshes[i].mPos); + tag->setOrientation(meshes[i].mRot); + tag->setScale(Ogre::Vector3(meshes[i].mScale)); + } } } } From fc7590694d11a1e6281fa203102ef1e0074d645a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 05:43:37 -0800 Subject: [PATCH 486/916] Revert "Revert "Use a child scene node for the accumulation root"" This reverts commit 376dfed15ba01cee8d24d122dfafc797a86fd303. I was wrong. It's needed at least for NPCs since they're attaching multiple animated skeletons to an object, and they all need to be offset correctly. Would be nice to use a Node, Bone, or TagPoint instead of a hefty SceneNode, though. --- apps/openmw/mwrender/animation.cpp | 5 ++--- apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b63de2f16..b81104067 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -48,7 +48,7 @@ Animation::~Animation() void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { - mInsert = node; + mInsert = node->createChildSceneNode(); assert(mInsert); mEntityList = NifOgre::Loader::createEntities(mInsert, model); @@ -76,8 +76,7 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model if(data.isEmpty() || !Ogre::any_cast(data)) continue; - mAccumRoot = skelinst->getRootBone(); - mAccumRoot->setManuallyControlled(true); + mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 60e524d28..165a6525c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -22,7 +22,7 @@ protected: Ogre::SceneNode* mInsert; NifOgre::EntityList mEntityList; std::map mTextKeys; - Ogre::Bone *mAccumRoot; + Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mStartPosition; From c23a96d6065ae0ca8a452624be8711bff0985f8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 06:08:03 -0800 Subject: [PATCH 487/916] Run an aniamtion update after "playing" the inventory idle This is so all the NPC parts get updated correctly. --- apps/openmw/mwrender/characterpreview.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 5a1a93311..8f0440b11 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -145,6 +145,7 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->play("inventoryhandtohand", "start", false); + mAnimation->runAnimation(0.0f); } // -------------------------------------------------------------------------------------------------- From 67a1ec51665822ea03fa89906488a7872566f5c8 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Feb 2013 16:14:58 +0100 Subject: [PATCH 488/916] added provisional startup dialogue --- apps/opencs/CMakeLists.txt | 4 +-- apps/opencs/editor.cpp | 46 ++++++++++++++++++++++++++-- apps/opencs/editor.hpp | 7 ++++- apps/opencs/view/doc/startup.cpp | 20 ++++++++++++ apps/opencs/view/doc/startup.hpp | 24 +++++++++++++++ apps/opencs/view/doc/view.cpp | 4 +++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/doc/viewmanager.cpp | 1 + apps/opencs/view/doc/viewmanager.hpp | 2 ++ 9 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 apps/opencs/view/doc/startup.cpp create mode 100644 apps/opencs/view/doc/startup.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index abbc953ca..d3634a66e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -12,7 +12,7 @@ set (OPENCS_SRC model/tools/mandatoryid.cpp model/tools/reportmodel.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp - view/doc/subview.cpp + view/doc/subview.cpp view/doc/startup.cpp view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp view/world/dialoguesubview.cpp @@ -33,7 +33,7 @@ set (OPENCS_HDR model/tools/mandatoryid.hpp model/tools/reportmodel.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp - view/doc/subview.hpp view/doc/subviewfactoryimp.hpp + view/doc/subview.hpp view/doc/subviewfactoryimp.hpp view/doc/startup.hpp view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp view/world/dialoguesubview.hpp diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 1632ed220..2340c71ee 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -11,10 +11,19 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) { connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); + connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); + + connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); + connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); } void CS::Editor::createDocument() { + mStartup.hide(); + + /// \todo open the ESX picker instead + /// \todo remove the following code for creating initial records into the document manager + std::ostringstream stream; stream << "NewDocument" << (++mNewDocumentIndex); @@ -23,7 +32,39 @@ void CS::Editor::createDocument() static const char *sGlobals[] = { - "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + }; + + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global record; + record.mId = sGlobals[i]; + record.mValue = i==0 ? 1 : 0; + record.mType = ESM::VT_Float; + document->getData().getGlobals().add (record); + } + + document->getData().merge(); /// \todo remove once proper ESX loading is implemented + + mViewManager.addView (document); +} + +void CS::Editor::loadDocument() +{ + mStartup.hide(); + + /// \todo open the ESX picker instead + /// \todo replace the manual record creation and load the ESX files instead + + std::ostringstream stream; + + stream << "Document" << (++mNewDocumentIndex); + + CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); + + static const char *sGlobals[] = + { + "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 }; for (int i=0; sGlobals[i]; ++i) @@ -42,8 +83,7 @@ void CS::Editor::createDocument() int CS::Editor::run() { - /// \todo Instead of creating an empty document, open a small welcome dialogue window with buttons for new/load/recent projects - createDocument(); + mStartup.show(); return QApplication::exec(); } \ No newline at end of file diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 60f7beaf1..0cd780f7f 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -4,7 +4,9 @@ #include #include "model/doc/documentmanager.hpp" + #include "view/doc/viewmanager.hpp" +#include "view/doc/startup.hpp" namespace CS { @@ -16,6 +18,7 @@ namespace CS CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; + CSVDoc::StartupDialogue mStartup; // not implemented Editor (const Editor&); @@ -28,9 +31,11 @@ namespace CS int run(); ///< \return error status - public slots: + private slots: void createDocument(); + + void loadDocument(); }; } diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp new file mode 100644 index 000000000..7861a1c2e --- /dev/null +++ b/apps/opencs/view/doc/startup.cpp @@ -0,0 +1,20 @@ + +#include "startup.hpp" + +#include +#include + +CSVDoc::StartupDialogue::StartupDialogue() +{ + QHBoxLayout *layout = new QHBoxLayout (this); + + QPushButton *createDocument = new QPushButton ("new", this); + connect (createDocument, SIGNAL (clicked()), this, SIGNAL (createDocument())); + layout->addWidget (createDocument); + + QPushButton *loadDocument = new QPushButton ("load", this); + connect (loadDocument, SIGNAL (clicked()), this, SIGNAL (loadDocument())); + layout->addWidget (loadDocument); + + setLayout (layout); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/startup.hpp b/apps/opencs/view/doc/startup.hpp new file mode 100644 index 000000000..f24d2a64b --- /dev/null +++ b/apps/opencs/view/doc/startup.hpp @@ -0,0 +1,24 @@ +#ifndef CSV_DOC_STARTUP_H +#define CSV_DOC_STARTUP_H + +#include + +namespace CSVDoc +{ + class StartupDialogue : public QWidget + { + Q_OBJECT + + public: + + StartupDialogue(); + + signals: + + void createDocument(); + + void loadDocument(); + }; +} + +#endif diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 13edb6e74..d6639e59c 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -32,6 +32,10 @@ void CSVDoc::View::setupFileMenu() connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); file->addAction (new_); + QAction *open = new QAction (tr ("Open"), this); + connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest())); + file->addAction (open); + mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index b1dedafe9..05d7210dc 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -84,6 +84,8 @@ namespace CSVDoc void newDocumentRequest(); + void loadDocumentRequest(); + public slots: void addSubView (const CSMWorld::UniversalId& id); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 22847c78b..b01b9ce34 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -57,6 +57,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) view->show(); connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest())); + connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); updateIndices(); diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 5e4b1be07..91a80d496 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -46,6 +46,8 @@ namespace CSVDoc void newDocumentRequest(); + void loadDocumentRequest(); + private slots: void documentStateChanged (int state, CSMDoc::Document *document); From 155cca0c9a23eec9db94f2e9214110029a0a4838 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sat, 2 Feb 2013 16:25:41 +0100 Subject: [PATCH 489/916] Upload missing files. Fix folder name. Keep Qt optional. Move open dialogue from doc to tools. Rename 'load' to 'open'. Deleted wrong comment. --- apps/launcher/graphicspage.cpp | 2 +- apps/launcher/maindialog.cpp | 2 +- apps/opencs/CMakeLists.txt | 8 +++--- apps/opencs/view/doc/opendialog.cpp | 27 +++++++++++++++++++ apps/opencs/view/doc/opendialog.hpp | 17 ++++++++++++ apps/opencs/view/doc/view.cpp | 16 +++++------ apps/opencs/view/doc/view.hpp | 6 ++--- components/CMakeLists.txt | 16 ++++++----- .../datafileslist.cpp | 0 .../datafileslist.hpp | 0 .../model/datafilesmodel.cpp | 0 .../model/datafilesmodel.hpp | 0 .../model/esm/esmfile.cpp | 0 .../model/esm/esmfile.hpp | 0 .../model/modelitem.cpp | 0 .../model/modelitem.hpp | 0 .../utils/filedialog.cpp | 0 .../utils/filedialog.hpp | 0 .../utils/lineedit.cpp | 0 .../utils/lineedit.hpp | 0 .../utils/naturalsort.cpp | 0 .../utils/naturalsort.hpp | 0 .../utils/profilescombobox.cpp | 0 .../utils/profilescombobox.hpp | 0 .../utils/textinputdialog.cpp | 0 .../utils/textinputdialog.hpp | 0 26 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 apps/opencs/view/doc/opendialog.cpp create mode 100644 apps/opencs/view/doc/opendialog.hpp rename components/{file_order_list => fileorderlist}/datafileslist.cpp (100%) rename components/{file_order_list => fileorderlist}/datafileslist.hpp (100%) rename components/{file_order_list => fileorderlist}/model/datafilesmodel.cpp (100%) rename components/{file_order_list => fileorderlist}/model/datafilesmodel.hpp (100%) rename components/{file_order_list => fileorderlist}/model/esm/esmfile.cpp (100%) rename components/{file_order_list => fileorderlist}/model/esm/esmfile.hpp (100%) rename components/{file_order_list => fileorderlist}/model/modelitem.cpp (100%) rename components/{file_order_list => fileorderlist}/model/modelitem.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/filedialog.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/filedialog.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/lineedit.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/lineedit.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/naturalsort.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/naturalsort.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/profilescombobox.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/profilescombobox.hpp (100%) rename components/{file_order_list => fileorderlist}/utils/textinputdialog.cpp (100%) rename components/{file_order_list => fileorderlist}/utils/textinputdialog.hpp (100%) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index e69a8c207..dee84498c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "graphicspage.hpp" diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 43b8f317a..7914650fe 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include "maindialog.hpp" #include "playpage.hpp" diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 68b22c10e..76d669e15 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -12,12 +12,12 @@ set (OPENCS_SRC model/tools/mandatoryid.cpp model/tools/reportmodel.cpp view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp - view/doc/subview.cpp + view/doc/subview.cpp view/doc/opendialog.cpp view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp view/world/dialoguesubview.cpp - view/tools/reportsubview.cpp view/tools/subviews.cpp view/tools/opendialog.cpp + view/tools/reportsubview.cpp view/tools/subviews.cpp ) set (OPENCS_HDR @@ -33,12 +33,12 @@ set (OPENCS_HDR model/tools/mandatoryid.hpp model/tools/reportmodel.hpp view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp - view/doc/subview.hpp view/doc/subviewfactoryimp.hpp + view/doc/subview.hpp view/doc/subviewfactoryimp.hpp view/doc/opendialog.hpp view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp view/world/dialoguesubview.hpp - view/tools/reportsubview.hpp view/tools/subviews.hpp view/tools/opendialog.hpp + view/tools/reportsubview.hpp view/tools/subviews.hpp ) set (OPENCS_US diff --git a/apps/opencs/view/doc/opendialog.cpp b/apps/opencs/view/doc/opendialog.cpp new file mode 100644 index 000000000..f51cbadb9 --- /dev/null +++ b/apps/opencs/view/doc/opendialog.cpp @@ -0,0 +1,27 @@ +#include +#include + +#include + +#include "opendialog.hpp" + +OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + mFileSelector = new DataFilesList(mCfgMgr, this); + layout->addWidget(mFileSelector); + mFileSelector->setupDataFiles(); + + buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + layout->addWidget(buttonBox); + + setLayout(layout); + setWindowTitle(tr("Open")); +} + +void OpenDialog::getFileList(std::vector& paths) +{ + mFileSelector->getSelectedFiles(paths); +} diff --git a/apps/opencs/view/doc/opendialog.hpp b/apps/opencs/view/doc/opendialog.hpp new file mode 100644 index 000000000..6355aea44 --- /dev/null +++ b/apps/opencs/view/doc/opendialog.hpp @@ -0,0 +1,17 @@ +#include +#include + +class DataFilesList; +class QDialogButtonBox; + +class OpenDialog : public QDialog { + Q_OBJECT +public: + OpenDialog(QWidget * parent = 0); + + void getFileList(std::vector& paths); +private: + DataFilesList * mFileSelector; + QDialogButtonBox * buttonBox; + Files::ConfigurationManager mCfgMgr; +}; \ No newline at end of file diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index ebcb9aaa7..112807cca 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -14,8 +14,7 @@ #include "../tools/subviews.hpp" -#include "../tools/opendialog.hpp" - +#include "opendialog.hpp" #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -34,9 +33,9 @@ void CSVDoc::View::setupFileMenu() connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); file->addAction (new_); - mLoad = new QAction(tr ("&Load"), this); - connect (mLoad, SIGNAL (triggered()), this, SLOT (load())); - file->addAction (mLoad); + mOpen = new QAction(tr ("&Open"), this); + connect (mOpen, SIGNAL (triggered()), this, SLOT (open())); + file->addAction (mOpen); mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); @@ -211,11 +210,11 @@ void CSVDoc::View::save() mDocument->save(); } -void CSVDoc::View::load() +void CSVDoc::View::open() { if (!mOpenDialog) { mOpenDialog = new OpenDialog(this); - connect(mOpenDialog, SIGNAL(accepted()), this, SLOT(loadNewFiles())); + connect(mOpenDialog, SIGNAL(accepted()), this, SLOT(openNewFiles())); } mOpenDialog->show(); @@ -223,9 +222,8 @@ void CSVDoc::View::load() mOpenDialog->activateWindow(); } -void CSVDoc::View::loadNewFiles() +void CSVDoc::View::openNewFiles() { - //FIXME close old files std::vector paths; mOpenDialog->getFileList(paths); //FIXME load new files diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 182252203..839edf0a5 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -37,7 +37,7 @@ namespace CSVDoc QAction *mUndo; QAction *mRedo; QAction *mSave; - QAction *mLoad; + QAction *mOpen; QAction *mVerify; std::vector mEditingActions; Operations *mOperations; @@ -95,8 +95,8 @@ namespace CSVDoc void newView(); - void load(); - void loadNewFiles(); + void open(); + void openNewFiles(); void save(); void verify(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3798f66b7..63a227621 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -66,15 +66,17 @@ add_component_dir (translation translation ) -add_component_qt_dir (file_order_list - datafileslist model/modelitem model/datafilesmodel model/esm/esmfile - utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort - ) +find_package(Qt4 COMPONENTS QtCore QtGui) -find_package(Qt4 COMPONENTS QtCore QtGUI REQUIRED) -include(${QT_USE_FILE}) +if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) + add_component_qt_dir (fileorderlist + datafileslist model/modelitem model/datafilesmodel model/esm/esmfile + utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort + ) -QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) + include(${QT_USE_FILE}) + QT4_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) +endif(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) include_directories(${BULLET_INCLUDE_DIRS}) diff --git a/components/file_order_list/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp similarity index 100% rename from components/file_order_list/datafileslist.cpp rename to components/fileorderlist/datafileslist.cpp diff --git a/components/file_order_list/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp similarity index 100% rename from components/file_order_list/datafileslist.hpp rename to components/fileorderlist/datafileslist.hpp diff --git a/components/file_order_list/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp similarity index 100% rename from components/file_order_list/model/datafilesmodel.cpp rename to components/fileorderlist/model/datafilesmodel.cpp diff --git a/components/file_order_list/model/datafilesmodel.hpp b/components/fileorderlist/model/datafilesmodel.hpp similarity index 100% rename from components/file_order_list/model/datafilesmodel.hpp rename to components/fileorderlist/model/datafilesmodel.hpp diff --git a/components/file_order_list/model/esm/esmfile.cpp b/components/fileorderlist/model/esm/esmfile.cpp similarity index 100% rename from components/file_order_list/model/esm/esmfile.cpp rename to components/fileorderlist/model/esm/esmfile.cpp diff --git a/components/file_order_list/model/esm/esmfile.hpp b/components/fileorderlist/model/esm/esmfile.hpp similarity index 100% rename from components/file_order_list/model/esm/esmfile.hpp rename to components/fileorderlist/model/esm/esmfile.hpp diff --git a/components/file_order_list/model/modelitem.cpp b/components/fileorderlist/model/modelitem.cpp similarity index 100% rename from components/file_order_list/model/modelitem.cpp rename to components/fileorderlist/model/modelitem.cpp diff --git a/components/file_order_list/model/modelitem.hpp b/components/fileorderlist/model/modelitem.hpp similarity index 100% rename from components/file_order_list/model/modelitem.hpp rename to components/fileorderlist/model/modelitem.hpp diff --git a/components/file_order_list/utils/filedialog.cpp b/components/fileorderlist/utils/filedialog.cpp similarity index 100% rename from components/file_order_list/utils/filedialog.cpp rename to components/fileorderlist/utils/filedialog.cpp diff --git a/components/file_order_list/utils/filedialog.hpp b/components/fileorderlist/utils/filedialog.hpp similarity index 100% rename from components/file_order_list/utils/filedialog.hpp rename to components/fileorderlist/utils/filedialog.hpp diff --git a/components/file_order_list/utils/lineedit.cpp b/components/fileorderlist/utils/lineedit.cpp similarity index 100% rename from components/file_order_list/utils/lineedit.cpp rename to components/fileorderlist/utils/lineedit.cpp diff --git a/components/file_order_list/utils/lineedit.hpp b/components/fileorderlist/utils/lineedit.hpp similarity index 100% rename from components/file_order_list/utils/lineedit.hpp rename to components/fileorderlist/utils/lineedit.hpp diff --git a/components/file_order_list/utils/naturalsort.cpp b/components/fileorderlist/utils/naturalsort.cpp similarity index 100% rename from components/file_order_list/utils/naturalsort.cpp rename to components/fileorderlist/utils/naturalsort.cpp diff --git a/components/file_order_list/utils/naturalsort.hpp b/components/fileorderlist/utils/naturalsort.hpp similarity index 100% rename from components/file_order_list/utils/naturalsort.hpp rename to components/fileorderlist/utils/naturalsort.hpp diff --git a/components/file_order_list/utils/profilescombobox.cpp b/components/fileorderlist/utils/profilescombobox.cpp similarity index 100% rename from components/file_order_list/utils/profilescombobox.cpp rename to components/fileorderlist/utils/profilescombobox.cpp diff --git a/components/file_order_list/utils/profilescombobox.hpp b/components/fileorderlist/utils/profilescombobox.hpp similarity index 100% rename from components/file_order_list/utils/profilescombobox.hpp rename to components/fileorderlist/utils/profilescombobox.hpp diff --git a/components/file_order_list/utils/textinputdialog.cpp b/components/fileorderlist/utils/textinputdialog.cpp similarity index 100% rename from components/file_order_list/utils/textinputdialog.cpp rename to components/fileorderlist/utils/textinputdialog.cpp diff --git a/components/file_order_list/utils/textinputdialog.hpp b/components/fileorderlist/utils/textinputdialog.hpp similarity index 100% rename from components/file_order_list/utils/textinputdialog.hpp rename to components/fileorderlist/utils/textinputdialog.hpp From f785659297abf4b23876a875f0da5bdcb0c39ee8 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sat, 2 Feb 2013 17:36:12 +0000 Subject: [PATCH 490/916] Implemented OnPCAdd special variable Had to edit OpAddItem in miscextensions.cpp, as local variables were not being initialised for items added through it. Does not get reset on drop, as per original morrowind. --- apps/openmw/mwscript/containerextensions.cpp | 8 ++++++ apps/openmw/mwworld/containerstore.cpp | 28 ++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 1fa69d1fd..4cce19b86 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -50,6 +50,14 @@ namespace MWScript MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item); ref.getPtr().getRefData().setCount (count); + + // Configure item's script variables + std::string script = MWWorld::Class::get(ref.getPtr()).getScript(ref.getPtr()); + if (script != "") + { + const ESM::Script *esmscript = MWBase::Environment::get().getWorld()->getStore().get().find (script); + ref.getPtr().getRefData().setLocals(*esmscript); + } MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index bca4073b5..31eabb342 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -8,9 +8,11 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/scriptmanager.hpp" #include "manualref.hpp" #include "refdata.hpp" @@ -83,9 +85,31 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) CellStore *cell; Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); - // Items in players inventory have cell set to 0, so their scripts will never be removed + if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) - cell = 0; + { + cell = 0; // Items in players inventory have cell set to 0, so their scripts will never be removed + + // Set OnPCAdd special variable, if it is declared + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex("onpcadd"); + char type = locals.getType("onpcadd"); + + if(index != -1) + { + switch(type) + { + case 's': + item.mRefData->getLocals().mShorts.at (index) = 1; break; + + case 'l': + item.mRefData->getLocals().mLongs.at (index) = 1; break; + + case 'f': + item.mRefData->getLocals().mFloats.at (index) = 1.0; break; + } + } + } else cell = player.getCell(); From c45b4d6072cf5c2fc043089dd1d4c309621d1596 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 22:27:08 -0800 Subject: [PATCH 491/916] Clean up some NIF warning reports --- components/nifogre/ogre_nif_loader.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 2da8033e6..8175279d0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -328,9 +328,14 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); + else + warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } + if(!(node->recType == Nif::RC_NiNode)) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + Nif::ExtraPtr e = node->extra; while(!e.empty()) { @@ -365,9 +370,8 @@ void loadResource(Ogre::Resource *resource) Ogre::Skeleton *skel = dynamic_cast(resource); OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); - Nif::NIFFile::ptr pnif(Nif::NIFFile::create (skel->getName())); - Nif::NIFFile & nif = *pnif.get (); - const Nif::Node *node = dynamic_cast(nif.getRecord(0)); + Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); + const Nif::Node *node = static_cast(nif->getRecord(0)); std::vector ctrls; Ogre::Bone *animroot = NULL; @@ -406,7 +410,7 @@ void loadResource(Ogre::Resource *resource) if(!animroot) { warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ - skel->getName()+", but no text keys. Uses NiBSAnimationNode?"); + skel->getName()+", but no text keys."); return; } @@ -1037,7 +1041,6 @@ public: while(!e.empty()) { Nif::NiStringExtraData *sd; - Nif::NiTextKeyExtraData *td; if((sd=dynamic_cast(e.getPtr())) != NULL) { // String markers may contain important information @@ -1049,12 +1052,6 @@ public: flags |= 0x01; } } - else if((td=dynamic_cast(e.getPtr())) != NULL) - { - // TODO: Read and store text keys somewhere - } - else - warn("Unhandled extra data type "+e->recName); e = e->extra; } @@ -1087,9 +1084,6 @@ public: meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); } - else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && - node->recType != Nif::RC_NiRotatingParticles) - warn("Unhandled mesh node type: "+node->recName); const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) From 007a5963de20e6a123e4d1519e62397a6d385b67 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Feb 2013 23:39:43 -0800 Subject: [PATCH 492/916] Handle most state changes in the character controller when setting the movement vector --- apps/openmw/mwmechanics/actors.cpp | 34 ++++----------------------- apps/openmw/mwmechanics/character.cpp | 29 ++++++++++++++++++----- apps/openmw/mwmechanics/character.hpp | 2 +- 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 27b7ad14e..2466b8a86 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -211,8 +211,7 @@ namespace MWMechanics float totalDuration = mDuration; mDuration = 0; - PtrControllerMap::iterator iter(mActors.begin()); - while(iter != mActors.end()) + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { @@ -224,10 +223,7 @@ namespace MWMechanics updateNpc(iter->first, totalDuration, paused); if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) - { - iter++; continue; - } } // workaround: always keep player alive for now @@ -244,18 +240,14 @@ namespace MWMechanics } MWWorld::Class::get(iter->first).getCreatureStats(iter->first).resurrect(); - ++iter; continue; } if(iter->second.getState() == CharState_Dead) - { - iter++; continue; - } + iter->second.setMovementVector(Ogre::Vector3::ZERO); iter->second.setState(CharState_Dead, false); - iter->second.setDirection(Ogre::Vector3::ZERO); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -272,26 +264,8 @@ namespace MWMechanics if(iter->second.getState() == CharState_Dead) continue; - Ogre::Vector3 dir = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - CharacterState newstate = CharState_Idle; - - if(dir.length() >= 0.1f) - { - if(std::abs(dir.x/2.0f) > std::abs(dir.y)) - { - if(dir.x > 0.0f) - newstate = CharState_WalkRight; - else if(dir.x < 0.0f) - newstate = CharState_WalkLeft; - } - else if(dir.y < 0.0f) - newstate = CharState_WalkBack; - else - newstate = CharState_WalkForward; - } - - iter->second.setState(newstate, true); - iter->second.setDirection(dir); + Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); + iter->second.setMovementVector(movement); } std::vector > movement; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6e78adfa4..677ffcf23 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -127,14 +127,31 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -void CharacterController::setDirection(const Ogre::Vector3 &dir) +void CharacterController::setMovementVector(const Ogre::Vector3 &vec) { - // HACK: The direction length we get is too large. - float mult = dir.length() / 32.0f; - mult = std::max(1.0f, mult); + // HACK: The length we get is too large. + float speed = std::max(1.0f, vec.length() / 32.0f); + + if(vec.length() >= 0.1f) + { + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + { + if(vec.x > 0.0f) + setState(CharState_WalkRight, true); + else if(vec.x < 0.0f) + setState(CharState_WalkLeft, true); + } + else if(vec.y < 0.0f) + setState(CharState_WalkBack, true); + else + setState(CharState_WalkForward, true); + } + else + setState(CharState_Idle, true); + if(mAnimation) - mAnimation->setSpeedMult(mult); - mDirection = dir.normalisedCopy(); + mAnimation->setSpeedMult(speed); + mDirection = vec.normalisedCopy(); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 53349c841..e5c7a4b8c 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -53,7 +53,7 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setDirection(const Ogre::Vector3 &dir); + void setMovementVector(const Ogre::Vector3 &vec); void setState(CharacterState state, bool loop); CharacterState getState() const From 7fe877d8eab4a53dc70f23de52b0fb26493b0d7d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 00:19:22 -0800 Subject: [PATCH 493/916] Add a couple more character states --- apps/openmw/mwmechanics/actors.cpp | 10 +++++----- apps/openmw/mwmechanics/character.cpp | 16 ++++++++++++++-- apps/openmw/mwmechanics/character.hpp | 15 ++++++++++++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2466b8a86..df0d6a5e8 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -169,7 +169,7 @@ namespace MWMechanics if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); else - mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Dead, false))); + mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Death1, false))); } void Actors::removeActor (const MWWorld::Ptr& ptr) @@ -215,7 +215,7 @@ namespace MWMechanics { if(!MWWorld::Class::get(iter->first).getCreatureStats(iter->first).isDead()) { - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) iter->second.setState(CharState_Idle, true); updateActor(iter->first, totalDuration); @@ -243,11 +243,11 @@ namespace MWMechanics continue; } - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) continue; iter->second.setMovementVector(Ogre::Vector3::ZERO); - iter->second.setState(CharState_Dead, false); + iter->second.setState(CharState_Death1, false); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -261,7 +261,7 @@ namespace MWMechanics { for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - if(iter->second.getState() == CharState_Dead) + if(iter->second.getState() >= CharState_Death1) continue; Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 677ffcf23..4f8525eca 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -37,13 +37,25 @@ static const struct { Ogre::Vector3 accumulate; } sStateList[] = { { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle2, "idle2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle3, "idle3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle4, "idle4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle5, "idle5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle6, "idle6", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle7, "idle7", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle8, "idle8", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle9, "idle9", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, - { CharState_Dead, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death1, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death2, "death2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death3, "death3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death4, "death4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death5, "death5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, }; static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); @@ -162,7 +174,7 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_Idle || getState() == CharState_Dead)) + if(!(getState() == CharState_Idle || getState() >= CharState_Death1)) { movement = mDirection * movement.length(); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index e5c7a4b8c..c8e92f7a9 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -15,13 +15,26 @@ namespace MWMechanics enum CharacterState { CharState_Idle, + CharState_Idle2, + CharState_Idle3, + CharState_Idle4, + CharState_Idle5, + CharState_Idle6, + CharState_Idle7, + CharState_Idle8, + CharState_Idle9, CharState_WalkForward, CharState_WalkBack, CharState_WalkLeft, CharState_WalkRight, - CharState_Dead + /* Must be last! */ + CharState_Death1, + CharState_Death2, + CharState_Death3, + CharState_Death4, + CharState_Death5 }; class CharacterController From 60a75cb5ee77453d7d33db421bee3cf2d0eb61f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 00:54:50 -0800 Subject: [PATCH 494/916] Make sure to keep the character preview animation updated --- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8f0440b11..24df30556 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -121,7 +121,8 @@ namespace MWRender void InventoryPreview::update(int sizeX, int sizeY) { - mAnimation->forceUpdate (); + mAnimation->runAnimation(0.0f); + mAnimation->forceUpdate(); mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); @@ -145,7 +146,6 @@ namespace MWRender mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); mAnimation->play("inventoryhandtohand", "start", false); - mAnimation->runAnimation(0.0f); } // -------------------------------------------------------------------------------------------------- From 23acf4b130e10213403b3655dca97eeb13f5808b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 01:38:42 -0800 Subject: [PATCH 495/916] Don't break right away when the animation time remaining is 0 --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b81104067..0e906181c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -225,7 +225,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) Ogre::Vector3 movement = Ogre::Vector3::ZERO; timepassed *= mAnimSpeedMult; - while(mCurrentAnim && mPlaying && timepassed > 0.0f) + while(mCurrentAnim && mPlaying) { float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 165a6525c..46a1ed88d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -44,6 +44,7 @@ protected: * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); + /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); @@ -52,6 +53,7 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); + void createEntityList(Ogre::SceneNode *node, const std::string &model); public: From d6a73a2a02d4d49bb733a59d8e1442ed819d831c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 Feb 2013 11:41:31 +0100 Subject: [PATCH 496/916] updated changelog --- readme.txt | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/readme.txt b/readme.txt index d94ccd7f0..91690ff57 100644 --- a/readme.txt +++ b/readme.txt @@ -94,6 +94,38 @@ Allowed options: CHANGELOG +0.21.0 + +Bug #253: Dialogs don't work for Russian version of Morrowind +Bug #267: Activating creatures without dialogue can still activate the dialogue GUI +Bug #354: True flickering lights +Bug #386: The main menu's first entry is wrong (in french) +Bug #479: Adding the spell "Ash Woe Blight" to the player causes strange attribute oscillations +Bug #495: Activation Range +Bug #497: Failed Disposition check doesn't stop a dialogue entry from being returned +Bug #498: Failing a disposition check shouldn't eliminate topics from the the list of those available +Bug #500: Disposition for most NPCs is 0/100 +Bug #501: Getdisposition command wrongly returns base disposition +Bug #506: Journal UI doesn't update anymore +Bug #507: EnableRestMenu is not a valid command - change it to EnableRest +Bug #508: Crash in Ald Daedroth Shrine +Bug #517: Wrong price calculation when untrading an item +Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin +Bug #524: Beast races are able to wear shoes +Bug #527: Background music fails to play +Bug #533: The arch at Gnisis entrance is not displayed +Bug #536: The same entry can be added multiple times to the journal +Bug #539: Race selection is broken +Feature #39: Video Playback +Feature #151: ^-escape sequences in text output +Feature #392: Add AI related script functions +Feature #456: Determine required ini fallback values and adjust the ini importer accordingly +Feature #460: Experimental DirArchives improvements +Feature #540: Execute scripts of objects in containers/inventories in active cells +Task #401: Review GMST fixing +Task #453: Unify case smashing/folding +Task #512: Rewrite utf8 component + 0.20.0 Bug #366: Changing the player's race during character creation does not change the look of the player character From a4872e321717ca7f3017bf5bbcbe36d2e8232da1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 Feb 2013 13:30:40 +0100 Subject: [PATCH 497/916] rewrote the opencs cmake scripts (more compact and no more annoying warnings) --- apps/opencs/CMakeLists.txt | 101 ++++++++++++++++++++++++------------- cmake/OpenMWMacros.cmake | 48 ++++++++++++++++++ 2 files changed, 113 insertions(+), 36 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index abbc953ca..d1cfbea52 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -1,46 +1,75 @@ -set (OPENCS_SRC - main.cpp editor.cpp +set (OPENCS_SRC main.cpp) - model/doc/documentmanager.cpp model/doc/document.cpp +opencs_units (. editor) - model/world/universalid.cpp model/world/idcollection.cpp model/world/data.cpp model/world/idtable.cpp - model/world/commands.cpp model/world/idtableproxymodel.cpp model/world/record.cpp - model/world/columnbase.cpp - model/tools/tools.cpp model/tools/operation.cpp model/tools/stage.cpp model/tools/verifier.cpp - model/tools/mandatoryid.cpp model/tools/reportmodel.cpp - - view/doc/viewmanager.cpp view/doc/view.cpp view/doc/operations.cpp view/doc/operation.cpp view/doc/subviewfactory.cpp - view/doc/subview.cpp - - view/world/table.cpp view/world/tablesubview.cpp view/world/subviews.cpp view/world/util.cpp - view/world/dialoguesubview.cpp - - view/tools/reportsubview.cpp view/tools/subviews.cpp +opencs_units (model/doc + document ) -set (OPENCS_HDR - editor.hpp - - model/doc/documentmanager.hpp model/doc/document.hpp model/doc/state.hpp - - model/world/universalid.hpp model/world/record.hpp model/world/idcollection.hpp model/world/data.hpp - model/world/idtable.hpp model/world/columns.hpp model/world/idtableproxymodel.hpp - model/world/commands.hpp model/world/columnbase.hpp - - model/tools/tools.hpp model/tools/operation.hpp model/tools/stage.hpp model/tools/verifier.hpp - model/tools/mandatoryid.hpp model/tools/reportmodel.hpp - - view/doc/viewmanager.hpp view/doc/view.hpp view/doc/operations.hpp view/doc/operation.hpp view/doc/subviewfactory.hpp - view/doc/subview.hpp view/doc/subviewfactoryimp.hpp - - view/world/table.hpp view/world/tablesubview.hpp view/world/subviews.hpp view/world/util.hpp - view/world/dialoguesubview.hpp - - view/tools/reportsubview.hpp view/tools/subviews.hpp +opencs_units_noqt (model/doc + documentmanager ) +opencs_hdrs_noqt (model/doc + state + ) + + +opencs_units (model/world + idtable idtableproxymodel + ) + +opencs_units_noqt (model/world + universalid data record idcollection commands columnbase + ) + +opencs_hdrs_noqt (model/world + columns + ) + + +opencs_units (model/tools + tools operation reportmodel + ) + +opencs_units_noqt (model/tools + stage verifier mandatoryid + ) + + +opencs_units (view/doc + viewmanager view operations operation subview + ) + +opencs_units_noqt (view/doc + subviewfactory + ) + +opencs_hdrs_noqt (view/doc + subviewfactoryimp + ) + + +opencs_units (view/world + table tablesubview + ) + +opencs_units_noqt (view/world + dialoguesubview util subviews + ) + + +opencs_units (view/tools + reportsubview + ) + +opencs_units_noqt (view/tools + subviews + ) + + set (OPENCS_US ) @@ -57,7 +86,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED) include(${QT_USE_FILE}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) -qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR}) +qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index e6f45fdb1..d13568a68 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -29,3 +29,51 @@ get_filename_component(filename ${f} NAME) configure_file(${source_dir}/${f} ${destination_dir}/${filename} COPYONLY) endforeach (f) endmacro (copy_all_files) + +macro (add_file project type file) +list (APPEND ${project}${type} ${file}) +endmacro (add_file) + +macro (add_unit project dir unit) +add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") +add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp") +endmacro (add_unit) + +macro (add_qt_unit project dir unit) +add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") +add_file (${project} _HDR_QT ${comp} "${dir}/${unit}.hpp") +add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp") +endmacro (add_qt_unit) + +macro (add_hdr project dir unit) +add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") +endmacro (add_hdr) + +macro (add_qt_hdr project dir unit) +add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") +add_file (${project} _HDR_QT ${comp} "${dir}/${unit}.hpp") +endmacro (add_qt_hdr) + +macro (opencs_units dir) +foreach (u ${ARGN}) +add_qt_unit (OPENCS ${dir} ${u}) +endforeach (u) +endmacro (opencs_units) + +macro (opencs_units_noqt dir) +foreach (u ${ARGN}) +add_unit (OPENCS ${dir} ${u}) +endforeach (u) +endmacro (opencs_units) + +macro (opencs_hdrs dir) +foreach (u ${ARGN}) +add_qt_hdr (OPENCS ${dir} ${u}) +endforeach (u) +endmacro (opencs_hdrs) + +macro (opencs_hdrs_noqt dir) +foreach (u ${ARGN}) +add_hdr (OPENCS ${dir} ${u}) +endforeach (u) +endmacro (opencs_hdrs) From c97553703a6f11d82d0e3c11bc2311ae5a1cb4d1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 Feb 2013 13:47:55 +0100 Subject: [PATCH 498/916] fixes for static build without cg --- apps/openmw/CMakeLists.txt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090..e2cb0e5c4 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -72,15 +72,20 @@ add_openmw_dir (mwbase ) # Main executable + IF(OGRE_STATIC) +ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) +set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) IF(WIN32) -ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager -DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL) -set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) -ELSE(WIN32) -ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager -DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) -set(OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${Cg_LIBRARIES} ${OGRE_Plugin_OctreeSceneManager_LIBRARIES} ${OGRE_Plugin_ParticleFX_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES}) +ADD_DEFINITIONS(-DENABLE_PLUGIN_Direct3D9) +list (APPEND OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_Direct3D9_LIBRARIES}) ENDIF(WIN32) +IF (Cg_FOUND) +ADD_DEFINITIONS(-DENABLE_PLUGIN_CgProgramManager) +list (APPEND OGRE_STATIC_PLUGINS ${OGRE_Plugin_CgProgramManager_LIBRARIES} ${Cg_LIBRARIES}) +ENDIF (Cg_FOUND) ENDIF(OGRE_STATIC) + add_executable(openmw ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} From ac112ef972927e96879405edca9aaf7c058440aa Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 3 Feb 2013 13:27:27 +0000 Subject: [PATCH 499/916] refactored special variable code --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 24 ++------------- apps/openmw/mwscript/locals.cpp | 41 ++++++++++++++++++++++++++ apps/openmw/mwscript/locals.hpp | 21 +++++-------- apps/openmw/mwworld/actionequip.cpp | 21 +------------ apps/openmw/mwworld/containerstore.cpp | 21 ++----------- apps/openmw/mwworld/worldimp.cpp | 22 ++------------ 7 files changed, 58 insertions(+), 94 deletions(-) create mode 100644 apps/openmw/mwscript/locals.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 482007090..f61f5ead2 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -41,7 +41,7 @@ add_openmw_dir (mwscript locals scriptmanagerimp compilercontext interpretercontext cellextensions miscextensions guiextensions soundextensions skyextensions statsextensions containerextensions aiextensions controlextensions extensions globalscripts ref dialogueextensions - animationextensions transformationextensions consoleextensions userextensions + animationextensions transformationextensions consoleextensions userextensions locals ) add_openmw_dir (mwsound diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ebbd69d80..40771af16 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -13,7 +13,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/scriptmanager.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -245,27 +244,10 @@ namespace MWGui invStore.equip(slot, invStore.end()); std::string script = MWWorld::Class::get(*it).getScript(*it); - /* Unset OnPCEquip Variable on item's script, if it has a script with that variable declared */ + // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared if(script != "") - { - Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); - int index = locals.getIndex("onpcequip"); - char type = locals.getType("onpcequip"); - if(index != -1) - { - switch(type) - { - case 's': - (*it).mRefData->getLocals().mShorts.at (index) = 0; break; - - case 'l': - (*it).mRefData->getLocals().mLongs.at (index) = 0; break; - - case 'f': - (*it).mRefData->getLocals().mFloats.at (index) = 0.0; break; - } - } - } + (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 0); + return; } } diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp new file mode 100644 index 000000000..53f744323 --- /dev/null +++ b/apps/openmw/mwscript/locals.cpp @@ -0,0 +1,41 @@ +#include "locals.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/scriptmanager.hpp" +#include + +namespace MWScript +{ + void Locals::configure (const ESM::Script& script) + { + mShorts.clear(); + mShorts.resize (script.mData.mNumShorts, 0); + mLongs.clear(); + mLongs.resize (script.mData.mNumLongs, 0); + mFloats.clear(); + mFloats.resize (script.mData.mNumFloats, 0); + } + + bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) + { + Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); + int index = locals.getIndex(var); + char type = locals.getType(var); + if(index != -1) + { + switch(type) + { + case 's': + mShorts.at (index) = val; break; + + case 'l': + mLongs.at (index) = val; break; + + case 'f': + mFloats.at (index) = val; break; + } + return true; + } + return false; + } +} diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index ec02e2f12..e933c727f 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -8,21 +8,16 @@ namespace MWScript { - struct Locals + class Locals { - std::vector mShorts; - std::vector mLongs; - std::vector mFloats; + public: + std::vector mShorts; + std::vector mLongs; + std::vector mFloats; + + void configure (const ESM::Script& script); + bool setVarByInt(const std::string& script, const std::string& var, int val); - void configure (const ESM::Script& script) - { - mShorts.clear(); - mShorts.resize (script.mData.mNumShorts, 0); - mLongs.clear(); - mLongs.resize (script.mData.mNumLongs, 0); - mFloats.clear(); - mFloats.resize (script.mData.mNumFloats, 0); - } }; } diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 2b238ead9..b1236f829 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -3,7 +3,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/scriptmanager.hpp" #include @@ -113,24 +112,6 @@ namespace MWWorld /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") - { - Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); - int index = locals.getIndex("onpcequip"); - char type = locals.getType("onpcequip"); - if(index != -1) - { - switch(type) - { - case 's': - (*it).mRefData->getLocals().mShorts.at (index) = 1; break; - - case 'l': - (*it).mRefData->getLocals().mLongs.at (index) = 1; break; - - case 'f': - (*it).mRefData->getLocals().mFloats.at (index) = 1.0; break; - } - } - } + (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 31eabb342..eb2a14d5b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -88,27 +88,10 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) { - cell = 0; // Items in players inventory have cell set to 0, so their scripts will never be removed + cell = 0; // Items in player's inventory have cell set to 0, so their scripts will never be removed // Set OnPCAdd special variable, if it is declared - Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); - int index = locals.getIndex("onpcadd"); - char type = locals.getType("onpcadd"); - - if(index != -1) - { - switch(type) - { - case 's': - item.mRefData->getLocals().mShorts.at (index) = 1; break; - - case 'l': - item.mRefData->getLocals().mLongs.at (index) = 1; break; - - case 'f': - item.mRefData->getLocals().mFloats.at (index) = 1.0; break; - } - } + item.mRefData->getLocals().setVarByInt(script, "onpcadd", 1); } else cell = player.getCell(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0c8027975..2926b76f8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1277,27 +1277,9 @@ namespace MWWorld { std::string script = MWWorld::Class::get(item).getScript(item); - /* Set OnPCDrop Variable on item's script, if it has a script with that variable declared */ + // Set OnPCDrop Variable on item's script, if it has a script with that variable declared if(script != "") - { - Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); - int index = locals.getIndex("onpcdrop"); - char type = locals.getType("onpcdrop"); - if(index != -1) - { - switch(type) - { - case 's': - item.mRefData->getLocals().mShorts.at (index) = 1; break; - - case 'l': - item.mRefData->getLocals().mLongs.at (index) = 1; break; - - case 'f': - item.mRefData->getLocals().mFloats.at (index) = 1.0; break; - } - } - } + item.mRefData->getLocals().setVarByInt(script, "onpcdrop", 1); } bool World::placeObject (const Ptr& object, float cursorX, float cursorY) From 15e51b76de89c8366d6573700f63f6f6290c7e3d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 15:46:23 +0100 Subject: [PATCH 500/916] Experimental: Directional shading on local map, separated out refraction render, no longer uses screen depth --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 9 ++-- apps/openmw/mwrender/localmap.cpp | 34 +++++++++---- apps/openmw/mwrender/localmap.hpp | 9 +++- apps/openmw/mwrender/npcanimation.cpp | 6 ++- apps/openmw/mwrender/occlusionquery.cpp | 7 ++- apps/openmw/mwrender/occlusionquery.hpp | 8 +++ apps/openmw/mwrender/refraction.cpp | 62 +++++++++++++++++++++++ apps/openmw/mwrender/refraction.hpp | 36 +++++++++++++ apps/openmw/mwrender/renderconst.hpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 53 ++++++++++++------- apps/openmw/mwrender/renderingmanager.hpp | 8 +-- apps/openmw/mwrender/ripplesimulation.cpp | 11 ++-- apps/openmw/mwrender/ripplesimulation.hpp | 3 -- apps/openmw/mwrender/sky.cpp | 4 ++ apps/openmw/mwrender/sky.hpp | 1 + apps/openmw/mwrender/water.cpp | 34 +++++++++---- apps/openmw/mwrender/water.hpp | 5 +- apps/openmw/mwworld/weather.cpp | 4 +- extern/shiny/Main/Factory.cpp | 2 - files/materials/openmw.configuration | 1 - files/materials/water.mat | 2 +- files/materials/water.shader | 22 ++------ libs/openengine/ogre/renderer.cpp | 13 +++++ 25 files changed, 250 insertions(+), 92 deletions(-) create mode 100644 apps/openmw/mwrender/refraction.cpp create mode 100644 apps/openmw/mwrender/refraction.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2c49e848e..94952329e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows - compositors characterpreview externalrendering globalmap videoplayer ripplesimulation + compositors characterpreview externalrendering globalmap videoplayer ripplesimulation refraction ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index dd5289edb..8fecf4c34 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -150,7 +150,7 @@ namespace MWGui if (!mFirstLoad) { mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName()); - mRectangle->setVisible(true); + //mRectangle->setVisible(true); } for (unsigned int i = 0; igetNumCompositors(); ++i) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index a172d02b1..704d0b6fd 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -59,7 +59,7 @@ namespace MWRender mNode = renderRoot->createChildSceneNode(); mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), RV_PlayerPreview); + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0); mNode->setVisible (false); @@ -81,7 +81,6 @@ namespace MWRender mViewport->setOverlaysEnabled(false); mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); mViewport->setShadowsEnabled(false); - mViewport->setVisibilityMask (RV_PlayerPreview); mRenderTarget->setActive(true); mRenderTarget->setAutoUpdated (false); @@ -102,7 +101,7 @@ namespace MWRender delete mAnimation; mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), RV_PlayerPreview); + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0); mNode->setVisible (false); @@ -118,6 +117,7 @@ namespace MWRender InventoryPreview::InventoryPreview(MWWorld::Ptr character) : CharacterPreview(character, 512, 1024, "CharacterPreview", Ogre::Vector3(0, 65, -180), Ogre::Vector3(0,65,0)) + , mSelectionBuffer(NULL) { } @@ -149,7 +149,8 @@ namespace MWRender void InventoryPreview::onSetup () { - mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); + if (!mSelectionBuffer) + mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); mAnimation->playGroup ("inventoryhandtohand", 0, 1); mAnimation->runAnimation (0); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b34942d28..1d338df12 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -32,6 +32,12 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0)); mCameraNode->attachObject(mCellCamera); + + mLight = mRendering->getScene()->createLight(); + mLight->setType (Ogre::Light::LT_DIRECTIONAL); + mLight->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLight->setVisible (false); + mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); } LocalMap::~LocalMap() @@ -181,17 +187,14 @@ void LocalMap::render(const float x, const float y, const float zlow, const float zhigh, const float xw, const float yw, const std::string& texture) { - // disable fog - // changing FOG_MODE is not a solution when using shaders, thus we have to push linear start/end + // disable fog (only necessary for fixed function, the shader based + // materials already do this through local_map material configuration) const float fStart = mRendering->getScene()->getFogStart(); const float fEnd = mRendering->getScene()->getFogEnd(); const ColourValue& clr = mRendering->getScene()->getFogColour(); - mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, 1000000, 10000000); + mRendering->getScene()->setFog(FOG_NONE); // make everything visible - mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); - mRenderingManager->disableLights(); - mCameraNode->setPosition(Vector3(x, zhigh+100000, y)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite @@ -231,7 +234,8 @@ void LocalMap::render(const float x, const float y, // use fallback techniques without shadows and without mrt vp->setMaterialScheme("local_map"); - rtt->update(); + rtt->setAutoUpdated(true); + rtt->addListener(this); // create "fog of war" texture TexturePtr tex2 = TextureManager::getSingleton().createManual( @@ -263,12 +267,24 @@ void LocalMap::render(const float x, const float y, } } - mRenderingManager->enableLights(); - // re-enable fog mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd); } +void LocalMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) +{ + mRenderingManager->disableLights(true); + mLight->setVisible(true); + evt.source->setAutoUpdated(false); +} + +void LocalMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) +{ + mRenderingManager->enableLights(true); + mLight->setVisible(false); + evt.source->removeListener(this); +} + void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) { pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle); diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 1aedf1325..2b1aa3f62 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace MWWorld { @@ -17,7 +18,7 @@ namespace MWRender /// /// \brief Local map rendering /// - class LocalMap + class LocalMap : public Ogre::RenderTargetListener { public: LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering); @@ -69,6 +70,9 @@ namespace MWRender */ bool isPositionExplored (float nX, float nY, int x, int y, bool interior); + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + private: OEngine::Render::OgreRenderer* mRendering; MWRender::RenderingManager* mRenderingManager; @@ -90,6 +94,9 @@ namespace MWRender Ogre::SceneNode* mCameraPosNode; Ogre::SceneNode* mCameraRotNode; + // directional light from a fixed angle + Ogre::Light* mLight; + float mAngle; const Ogre::Vector2 rotatePoint(const Ogre::Vector2& p, const Ogre::Vector2& c, const float angle); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d33bdda91..52ad24523 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -95,7 +95,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->getUserObjectBindings ().setUserAny (Ogre::Any(-1)); - base->setVisibilityFlags(mVisibilityFlags); + if (mVisibilityFlags != 0) + base->setVisibilityFlags(mVisibilityFlags); bool transparent = false; for(unsigned int j=0;j < base->getNumSubEntities();++j) { @@ -362,7 +363,8 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) { - parts[i]->setVisibilityFlags(mVisibilityFlags); + if (mVisibilityFlags != 0) + parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->getUserObjectBindings ().setUserAny (Ogre::Any(group)); } return entities; diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 6d3f67de9..c9e649fe6 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -16,7 +16,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0), mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false), - mBBNode(0) + mBBNode(0), mActive(false) { mRendering = renderer; mSunNode = sunNode; @@ -108,8 +108,9 @@ bool OcclusionQuery::supported() void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass, const AutoParamDataSource* source, const LightList* pLightList, bool suppressRenderStateChanges) { + if (!mActive) return; // The following code activates and deactivates the occlusion queries - // so that the queries only include the rendering of their intended targets + // so that the queries only include the rendering of the intended meshes // Close the last occlusion query // Each occlusion query should only last a single rendering @@ -146,6 +147,8 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass void OcclusionQuery::renderQueueEnded(uint8 queueGroupId, const String& invocation, bool& repeatThisInvocation) { + if (!mActive) return; + if (mActiveQuery != NULL) { mActiveQuery->endOcclusionQuery(); diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index c76fcccd0..af6f668c1 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -29,6 +29,12 @@ namespace MWRender */ bool supported(); + /** + * make sure to disable occlusion queries before updating unrelated render targets + * @param active + */ + void setActive (bool active) { mActive = active; } + /** * per-frame update */ @@ -85,6 +91,8 @@ namespace MWRender bool mTestResult; + bool mActive; + bool mSupported; bool mDoQuery; bool mDoQuery2; diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp new file mode 100644 index 000000000..175b85223 --- /dev/null +++ b/apps/openmw/mwrender/refraction.cpp @@ -0,0 +1,62 @@ +#include "refraction.hpp" + +#include +#include +#include +#include +#include +#include + +#include "renderconst.hpp" + +namespace MWRender +{ + + Refraction::Refraction(Ogre::Camera *parentCamera) + : mParentCamera(parentCamera) + { + mCamera = mParentCamera->getSceneManager()->createCamera("RefractionCamera"); + + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("WaterRefraction", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); + + mRenderTarget = texture->getBuffer()->getRenderTarget(); + Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain); + mRenderTarget->setAutoUpdated(true); + mRenderTarget->addListener(this); + } + + Refraction::~Refraction() + { + Ogre::TextureManager::getSingleton().remove("WaterRefraction"); + mParentCamera->getSceneManager()->destroyCamera(mCamera); + mRenderTarget->removeListener(this); + } + + void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) + { + mParentCamera->getParentSceneNode ()->needUpdate (); + mCamera->setOrientation(mParentCamera->getDerivedOrientation()); + mCamera->setPosition(mParentCamera->getDerivedPosition()); + mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); + mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); + mCamera->setAspectRatio(mParentCamera->getAspectRatio()); + mCamera->setFOVy(mParentCamera->getFOVy()); + + mCamera->enableCustomNearClipPlane(mNearClipPlane); + } + + void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) + { + + } + + void Refraction::setWaterPlane(Ogre::Plane plane) + { + mNearClipPlane = Ogre::Plane(-plane.normal, - (plane.d + 5) ); + } + +} diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp new file mode 100644 index 000000000..01ec86521 --- /dev/null +++ b/apps/openmw/mwrender/refraction.hpp @@ -0,0 +1,36 @@ +#ifndef MWRENDER_REFRACTION_H +#define MWRENDER_REFRACTION_H + +#include +#include + +namespace Ogre +{ + class Camera; + class RenderTarget; +} + +namespace MWRender +{ + + class Refraction : public Ogre::RenderTargetListener + { + + public: + Refraction(Ogre::Camera* parentCamera); + ~Refraction(); + + void setWaterPlane (Ogre::Plane plane); + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + + private: + Ogre::Camera* mParentCamera; + Ogre::Camera* mCamera; + Ogre::RenderTarget* mRenderTarget; + Ogre::Plane mNearClipPlane; + }; + +} + +#endif diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 75e243ec7..ee7e023a1 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -54,9 +54,7 @@ enum VisibilityFlags RV_OcclusionQuery = 256, - RV_PlayerPreview = 512, - - RV_Debug = 1024, + RV_Debug = 512, RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3fed4d994..18337c7d7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -334,8 +334,13 @@ void RenderingManager::update (float duration, bool paused) mPlayer->setCameraDistance(test.second * orig.distance(dest), false, false); } } + mOcclusionQuery->update(duration); - + + // deactivate queries to make sure we aren't getting false results from several misc render targets + // (will be reactivated at the bottom of this method) + mOcclusionQuery->setActive(false); + mVideoPlayer->update (); mRendering.update(duration); @@ -391,6 +396,8 @@ void RenderingManager::update (float duration, bool paused) orig = Ogre::Vector3(orig.x, orig.z, -orig.y); mWater->update(duration, orig); } + + mOcclusionQuery->setActive(true); } void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) @@ -608,22 +615,28 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) mTerrainManager->setAmbient(colour); } -void RenderingManager::sunEnable() +void RenderingManager::sunEnable(bool real) { - // Don't disable the light, as the shaders assume the first light to be directional. - //if (mSun) mSun->setVisible(true); - mSunEnabled = true; + if (real && mSun) mSun->setVisible(true); + else + { + // Don't disable the light, as the shaders assume the first light to be directional. + mSunEnabled = true; + } } -void RenderingManager::sunDisable() +void RenderingManager::sunDisable(bool real) { - // Don't disable the light, as the shaders assume the first light to be directional. - //if (mSun) mSun->setVisible(false); - mSunEnabled = false; - if (mSun) + if (real && mSun) mSun->setVisible(false); + else { - mSun->setDiffuseColour(ColourValue(0,0,0)); - mSun->setSpecularColour(ColourValue(0,0,0)); + // Don't disable the light, as the shaders assume the first light to be directional. + mSunEnabled = false; + if (mSun) + { + mSun->setDiffuseColour(ColourValue(0,0,0)); + mSun->setSpecularColour(ColourValue(0,0,0)); + } } } @@ -654,16 +667,16 @@ void RenderingManager::preCellChange(MWWorld::Ptr::CellStore* cell) mLocalMap->saveFogOfWar(cell); } -void RenderingManager::disableLights() +void RenderingManager::disableLights(bool sun) { mObjects.disableLights(); - sunDisable(); + sunDisable(sun); } -void RenderingManager::enableLights() +void RenderingManager::enableLights(bool sun) { mObjects.enableLights(); - sunEnable(); + sunEnable(sun); } const bool RenderingManager::useMRT() @@ -867,14 +880,16 @@ void RenderingManager::applyCompositors() mCompositors->removeAll(); if (useMRT()) { + /* mCompositors->addCompositor("gbuffer", 0); mCompositors->setCompositorEnabled("gbuffer", true); mCompositors->addCompositor("gbufferFinalizer", 2); mCompositors->setCompositorEnabled("gbufferFinalizer", true); - } + */ +} - if (mWater) - mWater->assignTextures(); + //if (mWater) + //mWater->assignTextures(); } void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 68f2d79c3..0a92bb2ea 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -131,11 +131,11 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setAmbientColour(const Ogre::ColourValue& colour); void setSunColour(const Ogre::ColourValue& colour); void setSunDirection(const Ogre::Vector3& direction); - void sunEnable(); - void sunDisable(); + void sunEnable(bool real); ///< @param real whether or not to really disable the sunlight (otherwise just set diffuse to 0) + void sunDisable(bool real); - void disableLights(); - void enableLights(); + void disableLights(bool sun); ///< @param sun whether or not to really disable the sunlight (otherwise just set diffuse to 0) + void enableLights(bool sun); bool occlusionQuerySupported() { return mOcclusionQuery->supported(); } OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; } diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 6096c7ba3..043757e88 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -25,10 +25,6 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); - - mHeightToNormalMapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightToNormalMap"); - mHeightmapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightmapSimulation"); - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); mCamera = mSceneMgr->createCamera("RippleCamera"); @@ -46,7 +42,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); impulseNode->attachObject(mImpulse); - float w=0.05; + //float w=0.05; for (int i=0; i<4; ++i) { Ogre::TexturePtr texture; @@ -65,11 +61,11 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) rt->getViewport(0)->setClearEveryFrame(false); // debug overlay + /* Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true); debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false); w += 0.2; debugOverlay->setBoundingBox(aabInf); - Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode(); debugNode->attachObject(debugOverlay); @@ -83,6 +79,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i)); + */ mRenderTargets[i] = rt; mTextures[i] = texture; @@ -126,8 +123,6 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) // texture coordinate space mCurrentFrameOffset /= mRippleAreaLength; - std::cout << "Offset " << mCurrentFrameOffset << std::endl; - mRippleCenter = position; addImpulses(); diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 6096fa866..72ff3dbd8 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -43,9 +43,6 @@ private: // scenemanager to create the debug overlays on Ogre::SceneManager* mMainSceneMgr; - Ogre::MaterialPtr mHeightmapMaterial; - Ogre::MaterialPtr mHeightToNormalMapMaterial; - static const int TEX_NORMAL = 3; Ogre::Rectangle2D* mImpulse; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 60ecd4303..91277ebf6 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -628,6 +628,10 @@ void SkyManager::setLightningStrength(const float factor) else mLightning->setVisible(false); } +void SkyManager::setLightningEnabled(bool enabled) +{ + /// \todo +} void SkyManager::setLightningDirection(const Ogre::Vector3& dir) { diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index ee1360853..04d56d4af 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -167,6 +167,7 @@ namespace MWRender void setLightningStrength(const float factor); void setLightningDirection(const Ogre::Vector3& dir); + void setLightningEnabled(bool enabled); ///< disable prior to map render void setGlare(const float glare); void setGlareEnabled(bool enabled); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 6ee3890dd..0533388bc 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -13,6 +13,7 @@ #include "renderingmanager.hpp" #include "compositors.hpp" #include "ripplesimulation.hpp" +#include "refraction.hpp" #include #include @@ -85,7 +86,7 @@ PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* s mSceneMgr->addRenderQueueListener(this); mTexture = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_A8R8G8B8, TU_RENDERTARGET); + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET); mRenderTarget = mTexture->getBuffer()->getRenderTarget(); Viewport* vp = mRenderTarget->addViewport(mCamera); @@ -96,6 +97,7 @@ PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* s vp->setMaterialScheme("water_reflection"); mRenderTarget->addListener(this); mRenderTarget->setActive(true); + mRenderTarget->setAutoUpdated(true); sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName()); } @@ -104,6 +106,7 @@ PlaneReflection::~PlaneReflection () { mRenderTarget->removeListener (this); mSceneMgr->destroyCamera (mCamera); + mSceneMgr->removeRenderQueueListener(this); TextureManager::getSingleton ().remove("WaterReflection"); } @@ -127,7 +130,7 @@ void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::St } } -void PlaneReflection::preRenderTargetUpdate(const RenderTargetEvent& evt) +void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { mParentCamera->getParentSceneNode ()->needUpdate (); mCamera->setOrientation(mParentCamera->getDerivedOrientation()); @@ -144,7 +147,7 @@ void PlaneReflection::preRenderTargetUpdate(const RenderTargetEvent& evt) mCamera->enableReflection(mWaterPlane); } -void PlaneReflection::postRenderTargetUpdate(const RenderTargetEvent& evt) +void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { mSky->resetSkyPosition(); mCamera->disableReflection(); @@ -232,7 +235,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); m->setListener (this); - // ---------------------------------------------------------------------------------------------- // ---------------------------------- reflection debug overlay ---------------------------------- // ---------------------------------------------------------------------------------------------- @@ -296,6 +298,9 @@ Water::~Water() mWaterNode->detachObject(mWater); mSceneMgr->destroyEntity(mWater); mSceneMgr->destroySceneNode(mWaterNode); + + delete mReflection; + delete mRefraction; } void Water::changeCell(const ESM::Cell* cell) @@ -316,6 +321,8 @@ void Water::setHeight(const float height) if (mReflection) mReflection->setWaterPlane(mWaterPlane); + if (mRefraction) + mRefraction->setWaterPlane(mWaterPlane); mWaterNode->setPosition(0, height, 0); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); @@ -353,7 +360,7 @@ void Water::assignTextures() { if (Settings::Manager::getBool("shader", "Water")) { - +/* CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mRendering->getViewport())->getCompositor("gbuffer"); TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); @@ -361,6 +368,7 @@ void Water::assignTextures() TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1); sh::Factory::getInstance ().setTextureAlias ("SceneDepth", depthTexture->getName()); + */ } } @@ -397,15 +405,15 @@ void Water::update(float dt, Ogre::Vector3 player) mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); + + if (mReflection) + mReflection->update(); } void Water::applyRTT() { - if (mReflection) - { - delete mReflection; - mReflection = NULL; - } + delete mReflection; + mReflection = NULL; // Create rendertarget for reflection int rttsize = Settings::Manager::getInt("rtt size", "Water"); @@ -419,6 +427,12 @@ void Water::applyRTT() } else mWater->setRenderQueueGroup(RQG_Alpha); + + + delete mRefraction; + mRefraction = NULL; + + mRefraction = new Refraction(mCamera); } void Water::applyVisibilityMask() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 97eb590b3..67c788c81 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,12 +30,14 @@ namespace MWRender { class SkyManager; class RenderingManager; class RippleSimulation; + class Refraction; class Reflection { public: Reflection(Ogre::SceneManager* sceneManager) : mSceneMgr(sceneManager) {} + virtual ~Reflection() {} virtual void setWaterPlane (Ogre::Plane plane) {} virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } @@ -111,7 +113,6 @@ namespace MWRender { float mWaterTimer; - RippleSimulation* mSimulation; Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); @@ -132,6 +133,8 @@ namespace MWRender { int mVisibilityFlags; Reflection* mReflection; + Refraction* mRefraction; + RippleSimulation* mSimulation; public: Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 917a8d7d4..514276f9b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -718,14 +718,14 @@ void WeatherManager::update(float duration) mRendering->getSkyManager()->setLightningStrength(0.f); mRendering->setAmbientColour(result.mAmbientColor); - mRendering->sunEnable(); + mRendering->sunEnable(false); mRendering->setSunColour(result.mSunColor); mRendering->getSkyManager()->setWeather(result); } else { - mRendering->sunDisable(); + mRendering->sunDisable(false); mRendering->skyDisable(); mRendering->getSkyManager()->setLightningStrength(0.f); } diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 6e87800e5..82d664811 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -219,8 +219,6 @@ namespace sh break; } - std::cout << "loading " << it->first << std::endl; - MaterialInstance newInstance(it->first, this); newInstance.create(mPlatform); if (!mShadersEnabled) diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index ee97451d3..db3693dd6 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -10,7 +10,6 @@ configuration local_map { fog false mrt_output false - lighting false shadows false shadows_pssm false simple_water true diff --git a/files/materials/water.mat b/files/materials/water.mat index c427447d2..2717f26fc 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -20,7 +20,7 @@ material Water texture_unit refractionMap { - texture_alias WaterRefraction + direct_texture WaterRefraction tex_address_mode clamp } diff --git a/files/materials/water.shader b/files/materials/water.shader index 1e14dd596..dbe36a91c 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -201,13 +201,9 @@ SH_START_PROGRAM { - float2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1-shSaturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; - float depth = shSample(depthMap, screenCoords).x * far - depthPassthrough; - float shoreFade = shSaturate(depth / 50.0); - float2 nCoord = float2(0,0); nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); @@ -272,14 +268,8 @@ // refraction float3 R = reflect(vVec, normal); - - // check the depth at the refracted coords, and don't do any normal distortion for the refraction if the object to refract - // is actually above the water (objectDepth < waterDepth) - // this solves silhouettes around objects above the water - float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xz*REFR_BUMP)).x * far - depthPassthrough; - float doRefraction = (refractDepth < 0) ? 0.f : 1.f; - - float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(shoreFade * normal.xz*REFR_BUMP * doRefraction))*1.0).rgb); + + float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(normal.xz*REFR_BUMP))*1.0).rgb); // brighten up the refraction underwater refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction; @@ -288,10 +278,7 @@ float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; - - // smooth transition to shore (above water only) - shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, refraction, (1-shoreFade) * (1-isUnderwater)); - + // fog if (isUnderwater == 1) { @@ -319,8 +306,7 @@ } shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); - //shOutputColour(0).xyz = float3(relPos.x, relPos.y, 0); - shOutputColour(0).w = 1; + shOutputColour(0).w = 1; } #endif diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index ed5cc9b43..e6e1d46b8 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -210,11 +210,24 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& assert(mRoot); mRoot->initialise(false); + // create a hidden 1x1 background window to keep resources when recreating the secondary (real) window + /// \todo Why does this break occlusion queries? :( + /* + NameValuePairList params_; + params_.insert(std::make_pair("title", title)); + params_.insert(std::make_pair("FSAA", "0")); + params_.insert(std::make_pair("vsync", "false")); + params_.insert(std::make_pair("hidden", "true")); + Ogre::RenderWindow* hiddenWindow = mRoot->createRenderWindow("InactiveHidden", 1, 1, false, ¶ms_); + hiddenWindow->setActive(false); + */ + NameValuePairList params; params.insert(std::make_pair("title", title)); params.insert(std::make_pair("FSAA", settings.fsaa)); params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); + mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); // create the semi-transparent black background texture used by the GUI. From 51d5efeeb2df6a4be1b0c94df9a54011e60ddb2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 07:15:34 -0800 Subject: [PATCH 501/916] Work out the state in the character controller update method --- apps/openmw/mwmechanics/actors.cpp | 10 -------- apps/openmw/mwmechanics/character.cpp | 35 +++++++++++++-------------- apps/openmw/mwmechanics/character.hpp | 2 -- 3 files changed, 17 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index df0d6a5e8..c1f552ae4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -246,7 +246,6 @@ namespace MWMechanics if(iter->second.getState() >= CharState_Death1) continue; - iter->second.setMovementVector(Ogre::Vector3::ZERO); iter->second.setState(CharState_Death1, false); ++mDeathCount[MWWorld::Class::get(iter->first).getId(iter->first)]; @@ -259,15 +258,6 @@ namespace MWMechanics if(!paused) { - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) - { - if(iter->second.getState() >= CharState_Death1) - continue; - - Ogre::Vector3 movement = MWWorld::Class::get(iter->first).getMovementVector(iter->first); - iter->second.setMovementVector(movement); - } - std::vector > movement; for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4f8525eca..f5a4dda51 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -139,36 +139,35 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -void CharacterController::setMovementVector(const Ogre::Vector3 &vec) +Ogre::Vector3 CharacterController::update(float duration) { + const MWWorld::Class &cls = MWWorld::Class::get(mPtr); + const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + // HACK: The length we get is too large. float speed = std::max(1.0f, vec.length() / 32.0f); - if(vec.length() >= 0.1f) + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) - { - if(vec.x > 0.0f) - setState(CharState_WalkRight, true); - else if(vec.x < 0.0f) - setState(CharState_WalkLeft, true); - } - else if(vec.y < 0.0f) - setState(CharState_WalkBack, true); - else - setState(CharState_WalkForward, true); + if(vec.x > 0.0f) + setState(CharState_WalkRight, true); + else if(vec.x < 0.0f) + setState(CharState_WalkLeft, true); } + else if(vec.y > 0.0f) + setState(CharState_WalkForward, true); + else if(vec.y < 0.0f) + setState(CharState_WalkBack, true); else - setState(CharState_Idle, true); + { + if(!(getState() >= CharState_Death1)) + setState(CharState_Idle, true); + } if(mAnimation) mAnimation->setSpeedMult(speed); mDirection = vec.normalisedCopy(); -} - -Ogre::Vector3 CharacterController::update(float duration) -{ Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) movement += mAnimation->runAnimation(duration); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c8e92f7a9..69d73263b 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -66,8 +66,6 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); - void setMovementVector(const Ogre::Vector3 &vec); - void setState(CharacterState state, bool loop); CharacterState getState() const { return mState; } From a002b253d10fd882a29ef5917ac46f0cc281a932 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 3 Feb 2013 16:18:17 +0100 Subject: [PATCH 502/916] silenced a cmake warning --- cmake/OpenMWMacros.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index d13568a68..bb200ee57 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -64,7 +64,7 @@ macro (opencs_units_noqt dir) foreach (u ${ARGN}) add_unit (OPENCS ${dir} ${u}) endforeach (u) -endmacro (opencs_units) +endmacro (opencs_units_noqt) macro (opencs_hdrs dir) foreach (u ${ARGN}) @@ -76,4 +76,4 @@ macro (opencs_hdrs_noqt dir) foreach (u ${ARGN}) add_hdr (OPENCS ${dir} ${u}) endforeach (u) -endmacro (opencs_hdrs) +endmacro (opencs_hdrs_noqt) From 5334934612d49b065f71c78717c27c08d1e5ae2f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 18:03:09 +0100 Subject: [PATCH 503/916] Listen to render window updates and properly activate/deactivate occlusion queries pre/post update. --- apps/openmw/mwrender/refraction.cpp | 5 +++-- apps/openmw/mwrender/renderingmanager.cpp | 19 ++++++++++++++----- apps/openmw/mwrender/renderingmanager.hpp | 8 +++++++- apps/openmw/mwrender/water.cpp | 3 ++- libs/openengine/ogre/renderer.cpp | 1 - 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 175b85223..88ad70b7f 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -31,9 +31,9 @@ namespace MWRender Refraction::~Refraction() { + mRenderTarget->removeListener(this); Ogre::TextureManager::getSingleton().remove("WaterRefraction"); mParentCamera->getSceneManager()->destroyCamera(mCamera); - mRenderTarget->removeListener(this); } void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) @@ -56,7 +56,8 @@ namespace MWRender void Refraction::setWaterPlane(Ogre::Plane plane) { - mNearClipPlane = Ogre::Plane(-plane.normal, - (plane.d + 5) ); + /// \todo + mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,1,0), 0); } } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 18337c7d7..b2e18f1e8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -62,6 +62,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); mRendering.setWindowEventListener(this); + mRendering.getWindow()->addListener(this); + mCompositors = new Compositors(mRendering.getViewport()); mWater = 0; @@ -174,6 +176,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const RenderingManager::~RenderingManager () { + mRendering.getWindow()->removeListener(this); mRendering.removeWindowEventListener(this); delete mPlayer; @@ -337,10 +340,6 @@ void RenderingManager::update (float duration, bool paused) mOcclusionQuery->update(duration); - // deactivate queries to make sure we aren't getting false results from several misc render targets - // (will be reactivated at the bottom of this method) - mOcclusionQuery->setActive(false); - mVideoPlayer->update (); mRendering.update(duration); @@ -396,10 +395,20 @@ void RenderingManager::update (float duration, bool paused) orig = Ogre::Vector3(orig.x, orig.z, -orig.y); mWater->update(duration, orig); } +} +void RenderingManager::preRenderTargetUpdate(const RenderTargetEvent &evt) +{ mOcclusionQuery->setActive(true); } +void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt) +{ + // deactivate queries to make sure we aren't getting false results from several misc render targets + // (will be reactivated at the bottom of this method) + mOcclusionQuery->setActive(false); +} + void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) { const MWWorld::Store &lands = @@ -886,7 +895,7 @@ void RenderingManager::applyCompositors() mCompositors->addCompositor("gbufferFinalizer", 2); mCompositors->setCompositorEnabled("gbufferFinalizer", true); */ -} + } //if (mWater) //mWater->assignTextures(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0a92bb2ea..71ac742c2 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -11,6 +11,8 @@ #include +#include + #include "renderinginterface.hpp" #include "objects.hpp" @@ -47,7 +49,7 @@ namespace MWRender class GlobalMap; class VideoPlayer; -class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { +class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener, public Ogre::RenderTargetListener { private: @@ -137,6 +139,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void disableLights(bool sun); ///< @param sun whether or not to really disable the sunlight (otherwise just set diffuse to 0) void enableLights(bool sun); + + void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + bool occlusionQuerySupported() { return mOcclusionQuery->supported(); } OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0533388bc..4ef2aea66 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -185,6 +185,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mRendering(rend), mWaterTimer(0.f), mReflection(NULL), + mRefraction(NULL), mSimulation(NULL) { mSimulation = new RippleSimulation(mSceneMgr); @@ -317,7 +318,7 @@ void Water::setHeight(const float height) { mTop = height; - mWaterPlane = Plane(Vector3::UNIT_Y, height); + mWaterPlane = Plane(Vector3::UNIT_Y, -height); if (mReflection) mReflection->setWaterPlane(mWaterPlane); diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index e6e1d46b8..039aba226 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -211,7 +211,6 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& mRoot->initialise(false); // create a hidden 1x1 background window to keep resources when recreating the secondary (real) window - /// \todo Why does this break occlusion queries? :( /* NameValuePairList params_; params_.insert(std::make_pair("title", title)); From 979a874220267be05b290314846ce34bd054f4d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 19:01:59 +0100 Subject: [PATCH 504/916] Fixed the custom near clip planes --- apps/openmw/mwrender/refraction.cpp | 6 +++--- apps/openmw/mwrender/refraction.hpp | 2 +- apps/openmw/mwrender/water.cpp | 13 +++++++------ apps/openmw/mwrender/water.hpp | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 88ad70b7f..85642bc08 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -25,6 +25,7 @@ namespace MWRender vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain); + vp->setMaterialScheme("water_reflection"); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } @@ -54,10 +55,9 @@ namespace MWRender } - void Refraction::setWaterPlane(Ogre::Plane plane) + void Refraction::setHeight(float height) { - /// \todo - mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,1,0), 0); + mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,1,0), -(height + 5)); } } diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp index 01ec86521..e3777d9cf 100644 --- a/apps/openmw/mwrender/refraction.hpp +++ b/apps/openmw/mwrender/refraction.hpp @@ -20,7 +20,7 @@ namespace MWRender Refraction(Ogre::Camera* parentCamera); ~Refraction(); - void setWaterPlane (Ogre::Plane plane); + void setHeight (float height); void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 4ef2aea66..877a9a953 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -155,10 +155,10 @@ void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) mRenderActive = false; } -void PlaneReflection::setWaterPlane (Plane plane) +void PlaneReflection::setHeight (float height) { - mWaterPlane = plane; - mErrorPlane = Plane(plane.normal, mWaterPlane.d - 5); + mWaterPlane = Plane(Ogre::Vector3(0,1,0), height); + mErrorPlane = Plane(Ogre::Vector3(0,1,0), height - 5); } void PlaneReflection::setActive (bool active) @@ -321,9 +321,9 @@ void Water::setHeight(const float height) mWaterPlane = Plane(Vector3::UNIT_Y, -height); if (mReflection) - mReflection->setWaterPlane(mWaterPlane); + mReflection->setHeight(height); if (mRefraction) - mRefraction->setWaterPlane(mWaterPlane); + mRefraction->setHeight(height); mWaterNode->setPosition(0, height, 0); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); @@ -423,7 +423,7 @@ void Water::applyRTT() { mReflection = new PlaneReflection(mSceneMgr, mSky); mReflection->setParentCamera (mCamera); - mReflection->setWaterPlane(mWaterPlane); + mReflection->setHeight(mTop); mWater->setRenderQueueGroup(RQG_Water); } else @@ -434,6 +434,7 @@ void Water::applyRTT() mRefraction = NULL; mRefraction = new Refraction(mCamera); + mRefraction->setHeight(mTop); } void Water::applyVisibilityMask() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 67c788c81..cf181674a 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -39,7 +39,7 @@ namespace MWRender { : mSceneMgr(sceneManager) {} virtual ~Reflection() {} - virtual void setWaterPlane (Ogre::Plane plane) {} + virtual void setHeight (float height) {} virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } void setUnderwater(bool underwater) { mIsUnderwater = underwater; } virtual void setActive (bool active) {} @@ -72,7 +72,7 @@ namespace MWRender { PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky); virtual ~PlaneReflection(); - virtual void setWaterPlane (Ogre::Plane plane); + virtual void setHeight (float height); virtual void setActive (bool active); virtual void setVisibilityMask (int flags); From a44dfcd2acaf65ea657a14545b718718957e4872 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 19:28:31 +0100 Subject: [PATCH 505/916] Now that refraction is separated out, we don't have to worry about rendering order. Should fix transparency blending issues around water (eg waterfalls) for good. --- apps/openmw/mwrender/renderingmanager.cpp | 10 +++++----- apps/openmw/mwrender/water.cpp | 5 +---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b2e18f1e8..aa73bc49b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -867,8 +867,8 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw) mVideoPlayer->setResolution (rw->getWidth(), rw->getHeight()); const Settings::CategorySettingVector& changed = Settings::Manager::apply(); - MWBase::Environment::get().getInputManager()->processChangedSettings(changed); //FIXME - MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); // FIXME + MWBase::Environment::get().getInputManager()->processChangedSettings(changed); + MWBase::Environment::get().getWindowManager()->processChangedSettings(changed); } void RenderingManager::windowClosed(Ogre::RenderWindow* rw) @@ -878,9 +878,9 @@ void RenderingManager::windowClosed(Ogre::RenderWindow* rw) bool RenderingManager::waterShaderSupported() { - const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) - return false; + //const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); + //if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) + //return false; return true; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 877a9a953..0eb35323d 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -424,11 +424,8 @@ void Water::applyRTT() mReflection = new PlaneReflection(mSceneMgr, mSky); mReflection->setParentCamera (mCamera); mReflection->setHeight(mTop); - mWater->setRenderQueueGroup(RQG_Water); } - else - mWater->setRenderQueueGroup(RQG_Alpha); - + mWater->setRenderQueueGroup(RQG_Alpha); delete mRefraction; mRefraction = NULL; From 5cc8af0f14ff975899f2bfbc4e5801311e9191db Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 20:06:03 +0100 Subject: [PATCH 506/916] fix map positions --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- apps/openmw/mwrender/localmap.cpp | 27 +++++++++++++++------------ apps/openmw/mwrender/localmap.hpp | 8 ++++++++ apps/openmw/mwrender/water.cpp | 2 +- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 8fecf4c34..dd5289edb 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -150,7 +150,7 @@ namespace MWGui if (!mFirstLoad) { mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName()); - //mRectangle->setVisible(true); + mRectangle->setVisible(true); } for (unsigned int i = 0; igetNumCompositors(); ++i) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 1d338df12..3a906138b 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -187,15 +187,6 @@ void LocalMap::render(const float x, const float y, const float zlow, const float zhigh, const float xw, const float yw, const std::string& texture) { - // disable fog (only necessary for fixed function, the shader based - // materials already do this through local_map material configuration) - const float fStart = mRendering->getScene()->getFogStart(); - const float fEnd = mRendering->getScene()->getFogEnd(); - const ColourValue& clr = mRendering->getScene()->getFogColour(); - mRendering->getScene()->setFog(FOG_NONE); - - // make everything visible - mCameraNode->setPosition(Vector3(x, zhigh+100000, y)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite @@ -224,6 +215,9 @@ void LocalMap::render(const float x, const float y, TU_RENDERTARGET); RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); + + mCameraSettings[rtt] = Vector3(x, zhigh+100000, y); + rtt->setAutoUpdated(false); Viewport* vp = rtt->addViewport(mCellCamera); vp->setOverlaysEnabled(false); @@ -266,13 +260,19 @@ void LocalMap::render(const float x, const float y, //rtt->writeContentsToFile("./" + texture + ".jpg"); } } - - // re-enable fog - mRendering->getScene()->setFog(FOG_LINEAR, clr, 0, fStart, fEnd); } void LocalMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { + // disable fog (only necessary for fixed function, the shader based + // materials already do this through local_map material configuration) + mOldFogStart = mRendering->getScene()->getFogStart(); + mOldFogEnd = mRendering->getScene()->getFogEnd(); + mOldFogClr = mRendering->getScene()->getFogColour(); + mRendering->getScene()->setFog(FOG_NONE); + + mCellCamera->setPosition(mCameraSettings[evt.source]); + mRenderingManager->disableLights(true); mLight->setVisible(true); evt.source->setAutoUpdated(false); @@ -283,6 +283,9 @@ void LocalMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) mRenderingManager->enableLights(true); mLight->setVisible(false); evt.source->removeListener(this); + + // re-enable fog + mRendering->getScene()->setFog(FOG_LINEAR, mOldFogClr, 0, mOldFogStart, mOldFogEnd); } void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 2b1aa3f62..1f528f138 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace MWWorld @@ -120,6 +121,13 @@ namespace MWRender int mCellX, mCellY; Ogre::AxisAlignedBox mBounds; std::string mInteriorName; + + Ogre::ColourValue mOldFogClr; + float mOldFogStart; + float mOldFogEnd; + + // maps texture name to according camera settings + std::map mCameraSettings; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0eb35323d..f2854c879 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -401,7 +401,7 @@ void Water::update(float dt, Ogre::Vector3 player) mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - //if (player.y <= mTop) + if (player.y <= mTop) { mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } From fa07288b151d8c6addd9d42177737f29f9b82d78 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Feb 2013 20:29:50 +0100 Subject: [PATCH 507/916] tweaked map light color --- apps/openmw/mwrender/localmap.cpp | 4 ++++ apps/openmw/mwrender/localmap.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 3a906138b..ccad0a5e8 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -271,6 +271,9 @@ void LocalMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) mOldFogClr = mRendering->getScene()->getFogColour(); mRendering->getScene()->setFog(FOG_NONE); + mOldAmbient = mRendering->getScene()->getAmbientLight(); + mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); + mCellCamera->setPosition(mCameraSettings[evt.source]); mRenderingManager->disableLights(true); @@ -286,6 +289,7 @@ void LocalMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) // re-enable fog mRendering->getScene()->setFog(FOG_LINEAR, mOldFogClr, 0, mOldFogStart, mOldFogEnd); + mRendering->getScene()->setAmbientLight(mOldAmbient); } void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 1f528f138..afdf4b6e5 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -123,6 +123,7 @@ namespace MWRender std::string mInteriorName; Ogre::ColourValue mOldFogClr; + Ogre::ColourValue mOldAmbient; float mOldFogStart; float mOldFogEnd; From 91513206a01e5aa482d582f61179da93c9411ae1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Feb 2013 12:02:51 -0800 Subject: [PATCH 508/916] Don't use per-animation accumulation values This breaks walking diagonally and "jumping" (which technically wasn't jumping anyway). --- apps/openmw/mwmechanics/character.cpp | 70 ++++++++++++--------------- apps/openmw/mwmechanics/character.hpp | 2 - 2 files changed, 30 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f5a4dda51..fed6e3e3e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -34,39 +34,37 @@ namespace MWMechanics static const struct { CharacterState state; const char groupname[32]; - Ogre::Vector3 accumulate; } sStateList[] = { - { CharState_Idle, "idle", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle2, "idle2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle3, "idle3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle4, "idle4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle5, "idle5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle6, "idle6", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle7, "idle7", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle8, "idle8", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Idle9, "idle9", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Idle, "idle" }, + { CharState_Idle2, "idle2" }, + { CharState_Idle3, "idle3" }, + { CharState_Idle4, "idle4" }, + { CharState_Idle5, "idle5" }, + { CharState_Idle6, "idle6" }, + { CharState_Idle7, "idle7" }, + { CharState_Idle8, "idle8" }, + { CharState_Idle9, "idle9" }, - { CharState_WalkForward, "walkforward", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, - { CharState_WalkBack, "walkback", Ogre::Vector3(0.0f, 1.0f, 0.0f) }, - { CharState_WalkLeft, "walkleft", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, - { CharState_WalkRight, "walkright", Ogre::Vector3(1.0f, 0.0f, 0.0f) }, + { CharState_WalkForward, "walkforward" }, + { CharState_WalkBack, "walkback" }, + { CharState_WalkLeft, "walkleft" }, + { CharState_WalkRight, "walkright" }, - { CharState_Death1, "death1", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death2, "death2", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death3, "death3", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death4, "death4", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, - { CharState_Death5, "death5", Ogre::Vector3(1.0f, 1.0f, 0.0f) }, + { CharState_Death1, "death1" }, + { CharState_Death2, "death2" }, + { CharState_Death3, "death3" }, + { CharState_Death4, "death4" }, + { CharState_Death5, "death5" }, }; static const size_t sStateListSize = sizeof(sStateList)/sizeof(sStateList[0]); -static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 *accum) +static void getStateInfo(CharacterState state, std::string *group) { for(size_t i = 0;i < sStateListSize;i++) { if(sStateList[i].state == state) { *group = sStateList[i].groupname; - *accum = sStateList[i].accumulate; return; } } @@ -75,24 +73,25 @@ static void getStateInfo(CharacterState state, std::string *group, Ogre::Vector3 CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) - : mPtr(ptr), mAnimation(anim), mDirection(Ogre::Vector3::ZERO), mState(state), mSkipAnim(false) + : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { if(!mAnimation) return; mAnimation->setController(this); - Ogre::Vector3 accum; - getStateInfo(mState, &mCurrentGroup, &accum); - mAnimation->setAccumulation(accum); + getStateInfo(mState, &mCurrentGroup); + /* Accumulate along X/Y only for now, until we can figure out how we should + * handle knockout and death which moves the character down. */ + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) - , mCurrentGroup(rhs.mCurrentGroup), mDirection(rhs.mDirection) - , mState(rhs.mState), mSkipAnim(rhs.mSkipAnim) + , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) + , mSkipAnim(rhs.mSkipAnim) { if(!mAnimation) return; @@ -144,9 +143,6 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - // HACK: The length we get is too large. - float speed = std::max(1.0f, vec.length() / 32.0f); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) @@ -164,20 +160,17 @@ Ogre::Vector3 CharacterController::update(float duration) setState(CharState_Idle, true); } + // FIXME: The speed should actually be determined by the character's stance + // (running, sneaking, etc) and stats, rather than the length of the vector. + float speed = std::max(1.0f, vec.length() / 32.0f); if(mAnimation) mAnimation->setSpeedMult(speed); - mDirection = vec.normalisedCopy(); Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) movement += mAnimation->runAnimation(duration); mSkipAnim = false; - if(!(getState() == CharState_Idle || getState() >= CharState_Death1)) - { - movement = mDirection * movement.length(); - } - return movement; } @@ -196,7 +189,6 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_Idle; - mAnimation->setAccumulation(Ogre::Vector3::ZERO); mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) @@ -225,12 +217,10 @@ void CharacterController::setState(CharacterState state, bool loop) mAnimQueue.clear(); std::string anim; - Ogre::Vector3 accum; - getStateInfo(mState, &anim, &accum); + getStateInfo(mState, &anim); if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->setAccumulation(accum); mAnimation->play(mCurrentGroup, "start", loop); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 69d73263b..c5f29beef 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,8 +45,6 @@ class CharacterController typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; - Ogre::Vector3 mDirection; - std::string mCurrentGroup; CharacterState mState; bool mSkipAnim; From 4c973a0f6767570a4ed07d0265fe949e7f0f7beb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Feb 2013 13:46:54 +0100 Subject: [PATCH 509/916] constructing documents from a file list instead of a single name --- apps/opencs/editor.cpp | 12 +++++-- apps/opencs/model/doc/document.cpp | 42 +++++++++++++++++++++-- apps/opencs/model/doc/document.hpp | 10 ++++-- apps/opencs/model/doc/documentmanager.cpp | 5 +-- apps/opencs/model/doc/documentmanager.hpp | 7 +++- 5 files changed, 66 insertions(+), 10 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 2340c71ee..57e31e19e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -22,13 +22,16 @@ void CS::Editor::createDocument() mStartup.hide(); /// \todo open the ESX picker instead - /// \todo remove the following code for creating initial records into the document manager + /// \todo move the following code for creating initial records into the document manager std::ostringstream stream; stream << "NewDocument" << (++mNewDocumentIndex); - CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); + std::vector files; + files.push_back (stream.str()); + + CSMDoc::Document *document = mDocumentManager.addDocument (files, true); static const char *sGlobals[] = { @@ -60,7 +63,10 @@ void CS::Editor::loadDocument() stream << "Document" << (++mNewDocumentIndex); - CSMDoc::Document *document = mDocumentManager.addDocument (stream.str()); + std::vector files; + files.push_back (stream.str()); + + CSMDoc::Document *document = mDocumentManager.addDocument (files, false); static const char *sGlobals[] = { diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 9d2694483..93d664314 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,10 +1,48 @@ #include "document.hpp" -CSMDoc::Document::Document (const std::string& name) +#include + +void CSMDoc::Document::load (const std::vector::const_iterator& begin, + const std::vector::const_iterator& end) +{ + for (std::vector::const_iterator iter (begin); iter!=end; ++iter) + std::cout << "pretending to load " << iter->string() << std::endl; + + /// \todo load content files +} + +void CSMDoc::Document::createBase() +{ + std::cout << "pretending to create base file records" << std::endl; + + /// \todo create mandatory records for base content file +} + +CSMDoc::Document::Document (const std::vector& files, bool new_) : mTools (mData) { - mName = name; ///< \todo replace with ESX list + if (files.empty()) + throw std::runtime_error ("Empty content file sequence"); + + /// \todo adjust last file name: + /// \li make sure it is located in the data-local directory (adjust path if necessary) + /// \li make sure the extension matches the new scheme (change it if necesarry) + + mName = files.back().filename().string(); + + if (files.size()>1 || !new_) + { + std::vector::const_iterator end = files.end(); + + if (new_) + --end; + + load (files.begin(), end); + } + + if (new_ && files.size()==1) + createBase(); connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 43e8bba37..28cc19d44 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -3,6 +3,8 @@ #include +#include + #include #include #include @@ -38,10 +40,14 @@ namespace CSMDoc Document (const Document&); Document& operator= (const Document&); + void load (const std::vector::const_iterator& begin, + const std::vector::const_iterator& end); + + void createBase(); + public: - Document (const std::string& name); - ///< \todo replace name with ESX list + Document (const std::vector& files, bool new_); QUndoStack& getUndoStack(); diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index 8ae2764f2..740c0b582 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -14,9 +14,10 @@ CSMDoc::DocumentManager::~DocumentManager() delete *iter; } -CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::string& name) +CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector& files, + bool new_) { - Document *document = new Document (name); + Document *document = new Document (files, new_); mDocuments.push_back (document); diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 730c7fae1..a307b76a5 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace CSMDoc { class Document; @@ -21,8 +23,11 @@ namespace CSMDoc ~DocumentManager(); - Document *addDocument (const std::string& name); + Document *addDocument (const std::vector& files, bool new_); ///< The ownership of the returned document is not transferred to the caller. + /// + /// \param new_ Do not load the last content file in \a files and instead create in an + /// appropriate way. bool removeDocument (Document *document); ///< \return last document removed? From ba0d13fc12f2be6b483a09025b329f97974ae9b4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Feb 2013 13:50:38 +0100 Subject: [PATCH 510/916] moved code for creating new base content records into the Document class --- apps/opencs/editor.cpp | 19 +------------------ apps/opencs/model/doc/document.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 57e31e19e..7156db94e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -22,7 +22,6 @@ void CS::Editor::createDocument() mStartup.hide(); /// \todo open the ESX picker instead - /// \todo move the following code for creating initial records into the document manager std::ostringstream stream; @@ -33,22 +32,6 @@ void CS::Editor::createDocument() CSMDoc::Document *document = mDocumentManager.addDocument (files, true); - static const char *sGlobals[] = - { - "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 - }; - - for (int i=0; sGlobals[i]; ++i) - { - ESM::Global record; - record.mId = sGlobals[i]; - record.mValue = i==0 ? 1 : 0; - record.mType = ESM::VT_Float; - document->getData().getGlobals().add (record); - } - - document->getData().merge(); /// \todo remove once proper ESX loading is implemented - mViewManager.addView (document); } @@ -57,7 +40,7 @@ void CS::Editor::loadDocument() mStartup.hide(); /// \todo open the ESX picker instead - /// \todo replace the manual record creation and load the ESX files instead + /// \todo remove the manual record creation and load the ESX files instead std::ostringstream stream; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 93d664314..14e34d0ba 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -14,9 +14,19 @@ void CSMDoc::Document::load (const std::vector::const_i void CSMDoc::Document::createBase() { - std::cout << "pretending to create base file records" << std::endl; + static const char *sGlobals[] = + { + "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + }; - /// \todo create mandatory records for base content file + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global record; + record.mId = sGlobals[i]; + record.mValue = i==0 ? 1 : 0; + record.mType = ESM::VT_Float; + getData().getGlobals().add (record); + } } CSMDoc::Document::Document (const std::vector& files, bool new_) From 1747c1e01ac4729a37b328a89972c9143ab05e96 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 07:10:14 -0800 Subject: [PATCH 511/916] Integrate a new movement solver to handle object movement and collisions Temporary, and pretty breoken. Needs some serious integration fixes. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 7 + apps/openmw/mwmechanics/character.cpp | 32 ++++- apps/openmw/mwmechanics/character.hpp | 5 + apps/openmw/mwmechanics/movementsolver.cpp | 154 +++++++++++++++++++++ apps/openmw/mwmechanics/movementsolver.hpp | 37 +++++ apps/openmw/mwworld/worldimp.hpp | 4 + 7 files changed, 233 insertions(+), 8 deletions(-) create mode 100644 apps/openmw/mwmechanics/movementsolver.cpp create mode 100644 apps/openmw/mwmechanics/movementsolver.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 73baa4e72..5f425f7a0 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate + aiescort aiactivate movementsolver ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a426e3454..5f6e27867 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -20,6 +20,11 @@ namespace OEngine { class Fader; } + + namespace Physic + { + class PhysicEngine; + } } namespace ESM @@ -300,6 +305,8 @@ namespace MWBase /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const = 0; /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index fed6e3e3e..7962e197e 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -25,9 +25,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" +#include "movementsolver.hpp" + + namespace MWMechanics { @@ -75,6 +79,7 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { + mMovementSolver = new MovementSolver(mPtr); if(!mAnimation) return; @@ -93,12 +98,18 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { + mMovementSolver = new MovementSolver(mPtr); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ mAnimation->setController(this); } +CharacterController::~CharacterController() +{ + delete mMovementSolver; +} + void CharacterController::markerEvent(float time, const std::string &evt) { @@ -160,18 +171,25 @@ Ogre::Vector3 CharacterController::update(float duration) setState(CharState_Idle, true); } - // FIXME: The speed should actually be determined by the character's stance - // (running, sneaking, etc) and stats, rather than the length of the vector. - float speed = std::max(1.0f, vec.length() / 32.0f); - if(mAnimation) - mAnimation->setSpeedMult(speed); - Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) + { + // FIXME: The speed should actually be determined by the character's + // stance (running, sneaking, etc) and stats + mAnimation->setSpeedMult(1.0f); movement += mAnimation->runAnimation(duration); + } mSkipAnim = false; - return movement; + if(duration > 0.0f) + { + Ogre::Vector3 pos(mPtr.getCellRef().mPos.pos); + // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? + Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); + MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); + } + + return Ogre::Vector3(0.0f); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index c5f29beef..efd90ca19 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -13,6 +13,8 @@ namespace MWRender namespace MWMechanics { +class MovementSolver; + enum CharacterState { CharState_Idle, CharState_Idle2, @@ -49,6 +51,8 @@ class CharacterController CharacterState mState; bool mSkipAnim; + MovementSolver *mMovementSolver; + protected: /* Called by the animation whenever a new text key is reached. */ void markerEvent(float time, const std::string &evt); @@ -58,6 +62,7 @@ protected: public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); + virtual ~CharacterController(); Ogre::Vector3 update(float duration); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp new file mode 100644 index 000000000..219f077e4 --- /dev/null +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -0,0 +1,154 @@ +#include "movementsolver.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) + : mPtr(ptr) + , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) +{ +} + +MovementSolver::~MovementSolver() +{ + // nothing to do +} + +void MovementSolver::clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) +{ + //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. + //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. + float backoff; + + backoff = in.dotProduct(normal); + if(backoff < 0.0f) + backoff *= overbounce; + else + backoff /= overbounce; + + out = in - (normal*backoff); +} + +void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) +{ + Ogre::Vector3 normalizedDirection(direction); + normalizedDirection.normalise(); + + // no divide by normalizedDirection.length necessary because it's normalized + velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); +} + +bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) +{ + static const float maxslope = 45.0f; + traceResults trace; // no initialization needed + + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), + position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + halfExtents, verticalRotation, isInterior, mEngine); + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > maxslope)) + return false; + + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); + if(getSlope(trace.planenormal) < maxslope) + { + // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. + position = trace.endpos; + return true; + } + + return false; +} + +float MovementSolver::getSlope(const Ogre::Vector3 &normal) +{ + return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); +} + + +Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +{ + mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + + /* Anything to collide with? */ + if(1 || !mPhysicActor || !mPhysicActor->getCollisionMode()) + return position+movement; + + traceResults trace; //no initialization needed + int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + float maxslope=45; + + Ogre::Vector3 horizontalVelocity = movement/time; + Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); + + float remainingTime = time; + bool isInterior = !mPtr.getCell()->isExterior(); + float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); + + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); + if(trace.fraction < 1.0f) + { + if(getSlope(trace.planenormal) > maxslope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } + } + + do { + // trace to where character would go if there were no obstructions + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); + newPosition = trace.endpos; + currentNormal = trace.planenormal; + remainingTime = remainingTime * (1.0f-trace.fraction); + + // check for obstructions + if(trace.fraction != 1.0f) + { + //std::cout<<"angle: "< maxslope || currentNormal == lastNormal) + { + if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) + std::cout<< "stepped" < + +namespace MWMechanics +{ + class MovementSolver + { + public: + MovementSolver(const MWWorld::Ptr &ptr); + virtual ~MovementSolver(); + + Ogre::Vector3 move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + + private: + bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); + + void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce); + void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction); + + float getSlope(const Ogre::Vector3 &normal); + + MWWorld::Ptr mPtr; + OEngine::Physic::PhysicEngine *mEngine; + OEngine::Physic::PhysicActor *mPhysicActor; + + float verticalVelocity; + }; +} + +#endif /* GAME_MWMECHANICS_MOVEMENTSOLVER_H */ diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 4899a8807..062387e92 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -347,6 +347,10 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) + /// \todo Probably shouldn't be here + virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const + { return mPhysEngine; } + /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); From bf037b7d299c4ca0ebb4c50e9e656056f7f030e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Feb 2013 18:03:03 +0100 Subject: [PATCH 512/916] Removed problematic ModVertexAlpha method, now done in shader --- apps/openmw/mwrender/sky.cpp | 45 ---------------------------- apps/openmw/mwrender/sky.hpp | 2 -- extern/shiny/CMakeLists.txt | 7 ----- extern/shiny/Main/ShaderInstance.cpp | 20 ++++++------- files/materials/atmosphere.shader | 9 +++--- files/materials/clouds.shader | 9 +++--- 6 files changed, 18 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 60ecd4303..f8499d1e5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -203,48 +203,6 @@ unsigned int Moon::getPhaseInt() const return 0; } -void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) -{ - // Get the vertex colour buffer of this mesh - const Ogre::VertexElement* ves_diffuse = ent->getMesh()->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_DIFFUSE ); - HardwareVertexBufferSharedPtr colourBuffer = ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource()); - - // Lock - void* pData = colourBuffer->lock(HardwareBuffer::HBL_NORMAL); - - // Iterate over all vertices - int vertex_size = colourBuffer->getVertexSize(); - float * currentVertex = NULL; - for (unsigned int i=0; igetNumVertices(); ++i) - { - // Get a pointer to the vertex colour - ves_diffuse->baseVertexPointerToElement( pData, ¤tVertex ); - - unsigned char alpha=0; - if (meshType == 0) alpha = i%2 ? 0 : 255; // this is a cylinder, so every second vertex belongs to the bottom-most row - else if (meshType == 1) - { - if (i>= 49 && i <= 64) alpha = 0; // bottom-most row - else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row - else alpha = 255; - } - // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 - uint8 tmpR = static_cast(255); - uint8 tmpG = static_cast(255); - uint8 tmpB = static_cast(255); - uint8 tmpA = static_cast(alpha); - - // Modify - *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); - - // Move to the next vertex - pData = static_cast (pData) + vertex_size; - } - - // Unlock - ent->getMesh()->getSubMesh(0)->vertexData->vertexBufferBinding->getBuffer(ves_diffuse->getSource())->unlock(); -} - SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) : mHour(0.0f) , mDay(0) @@ -357,7 +315,6 @@ void SkyManager::create() atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); - ModVertexAlpha(atmosphere_ent, 0); } @@ -371,8 +328,6 @@ void SkyManager::create() clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); clouds_ent->setCastShadows(false); - - ModVertexAlpha(clouds_ent, 1); } mCreated = true; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index ee1360853..52fd7b4aa 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -218,8 +218,6 @@ namespace MWRender float mGlare; // target float mGlareFade; // actual - void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType); - bool mEnabled; bool mSunEnabled; bool mMasserEnabled; diff --git a/extern/shiny/CMakeLists.txt b/extern/shiny/CMakeLists.txt index 603336413..6eadcc167 100644 --- a/extern/shiny/CMakeLists.txt +++ b/extern/shiny/CMakeLists.txt @@ -24,13 +24,6 @@ set(SOURCE_FILES Main/ShaderSet.cpp ) -# In Debug mode, write the shader sources to the current directory -if (DEFINED CMAKE_BUILD_TYPE) - if (CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions(-DSHINY_WRITE_SHADER_DEBUG) - endif() -endif() - if (DEFINED SHINY_USE_WAVE_SYSTEM_INSTALL) # use system install else() diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp index 07ef8dfe2..0e074c7b4 100644 --- a/extern/shiny/Main/ShaderInstance.cpp +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -363,12 +363,12 @@ namespace sh if (Factory::getInstance ().getShaderDebugOutputEnabled ()) writeDebugFile(source, name + ".pre"); - else - { - #ifdef SHINY_WRITE_SHADER_DEBUG - writeDebugFile(source, name + ".pre"); - #endif - } + else + { + #ifdef SHINY_WRITE_SHADER_DEBUG + writeDebugFile(source, name + ".pre"); + #endif + } // why do we need our own preprocessor? there are several custom commands available in the shader files // (for example for binding uniforms to properties or auto constants) - more below. it is important that these @@ -648,12 +648,12 @@ namespace sh if (Factory::getInstance ().getShaderDebugOutputEnabled ()) writeDebugFile(source, name); - else - { + else + { #ifdef SHINY_WRITE_SHADER_DEBUG - writeDebugFile(source, name); + writeDebugFile(source, name); #endif - } + } if (!mProgram->getSupported()) { diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 295fa9376..16edc78c5 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -7,19 +7,18 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - shColourInput(float4) - shOutput(float4, colourPassthrough) + shOutput(float, alphaFade) SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); - colourPassthrough = colour; + alphaFade = shInputPosition.z < 150.0 ? 0.0 : 1.0; } #else SH_BEGIN_PROGRAM - shInput(float4, colourPassthrough) + shInput(float, alphaFade) #if MRT shDeclareMrtOutput(1) #endif @@ -27,7 +26,7 @@ SH_START_PROGRAM { - shOutputColour(0) = colourPassthrough * atmosphereColour; + shOutputColour(0) = atmosphereColour * float4(1,1,1,alphaFade); #if MRT shOutputColour(1) = float4(1,1,1,1); diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index f4258bf5d..9126ae423 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -8,21 +8,20 @@ shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) shVertexInput(float2, uv0) shOutput(float2, UV) - shColourInput(float4) - shOutput(float4, colourPassthrough) + shOutput(float, alphaFade) SH_START_PROGRAM { - colourPassthrough = colour; shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; + alphaFade = shInputPosition.z < 100.f ? 0 : 1; } #else SH_BEGIN_PROGRAM shInput(float2, UV) - shInput(float4, colourPassthrough) + shInput(float, alphaFade) #if MRT shDeclareMrtOutput(1) #endif @@ -42,7 +41,7 @@ float4 albedo = shSample(diffuseMap1, scrolledUV) * (1-cloudBlendFactor) + shSample(diffuseMap2, scrolledUV) * cloudBlendFactor; - shOutputColour(0) = colourPassthrough * float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity); + shOutputColour(0) = float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity * alphaFade); #if MRT shOutputColour(1) = float4(1,1,1,1); From a7d910614f516092cccc0ada7625de2e451e1902 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Feb 2013 18:04:09 +0100 Subject: [PATCH 513/916] extern/shiny update: made caching more robust --- extern/shiny/Main/Factory.cpp | 43 ++++++++++++++++++++++++---- extern/shiny/Main/Factory.hpp | 1 + extern/shiny/Main/ShaderInstance.cpp | 15 +--------- extern/shiny/Main/ShaderSet.cpp | 1 - extern/shiny/Main/ShaderSet.hpp | 7 ----- 5 files changed, 40 insertions(+), 27 deletions(-) diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 82d664811..c63a9e367 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -191,15 +191,48 @@ namespace sh &mGlobalSettings); int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceFile)); + mShadersLastModifiedNew[sourceFile] = lastModified; if (mShadersLastModified.find(sourceFile) != mShadersLastModified.end() && mShadersLastModified[sourceFile] != lastModified) { - newSet.markDirty (); + // delete any outdated shaders based on this shader set. + if ( boost::filesystem::exists(mPlatform->getCacheFolder()) + && boost::filesystem::is_directory(mPlatform->getCacheFolder())) + { + boost::filesystem::directory_iterator end_iter; + for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter) + { + if (boost::filesystem::is_regular_file(dir_iter->status()) ) + { + boost::filesystem::path file = dir_iter->path(); + + std::string pathname = file.filename().string(); + + // get first part of filename, e.g. main_fragment_546457654 -> main_fragment + // there is probably a better method for this... + std::vector tokens; + boost::split(tokens, pathname, boost::is_any_of("_")); + tokens.erase(--tokens.end()); + std::string shaderName; + for (std::vector::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();) + { + shaderName += *(vector_iter++); + if (vector_iter != tokens.end()) + shaderName += "_"; + } + + if (shaderName == it->first) + { + boost::filesystem::remove(file); + std::cout << "Removing outdated file: " << file << std::endl; + } + } + } + } + anyShaderDirty = true; } - mShadersLastModified[sourceFile] = lastModified; - mShaderSets.insert(std::make_pair(it->first, newSet)); } } @@ -313,11 +346,11 @@ namespace sh if (mReadSourceCache) { - // save the last modified time of shader sources + // save the last modified time of shader sources (as of when they were loaded) std::ofstream file; file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str()); - for (LastModifiedMap::const_iterator it = mShadersLastModified.begin(); it != mShadersLastModified.end(); ++it) + for (LastModifiedMap::const_iterator it = mShadersLastModifiedNew.begin(); it != mShadersLastModifiedNew.end(); ++it) { file << it->first << "\n" << it->second << std::endl; } diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp index 799dd71eb..1062c079c 100644 --- a/extern/shiny/Main/Factory.hpp +++ b/extern/shiny/Main/Factory.hpp @@ -185,6 +185,7 @@ namespace sh ConfigurationMap mConfigurations; LodConfigurationMap mLodConfigurations; LastModifiedMap mShadersLastModified; + LastModifiedMap mShadersLastModifiedNew; PropertySetGet mGlobalSettings; diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp index 0e074c7b4..1539128ab 100644 --- a/extern/shiny/Main/ShaderInstance.cpp +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -337,8 +337,7 @@ namespace sh size_t pos; bool readCache = Factory::getInstance ().getReadSourceCache () && boost::filesystem::exists( - Factory::getInstance ().getCacheFolder () + "/" + mName) - && !mParent->isDirty (); + Factory::getInstance ().getCacheFolder () + "/" + mName); bool writeCache = Factory::getInstance ().getWriteSourceCache (); @@ -363,12 +362,6 @@ namespace sh if (Factory::getInstance ().getShaderDebugOutputEnabled ()) writeDebugFile(source, name + ".pre"); - else - { - #ifdef SHINY_WRITE_SHADER_DEBUG - writeDebugFile(source, name + ".pre"); - #endif - } // why do we need our own preprocessor? there are several custom commands available in the shader files // (for example for binding uniforms to properties or auto constants) - more below. it is important that these @@ -648,12 +641,6 @@ namespace sh if (Factory::getInstance ().getShaderDebugOutputEnabled ()) writeDebugFile(source, name); - else - { -#ifdef SHINY_WRITE_SHADER_DEBUG - writeDebugFile(source, name); -#endif - } if (!mProgram->getSupported()) { diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp index 2702ece19..413d7d1a2 100644 --- a/extern/shiny/Main/ShaderSet.cpp +++ b/extern/shiny/Main/ShaderSet.cpp @@ -17,7 +17,6 @@ namespace sh , mName(name) , mCgProfile(cgProfile) , mHlslProfile(hlslProfile) - , mIsDirty(false) { if (type == "vertex") mType = GPT_Vertex; diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp index 776750598..a423b6779 100644 --- a/extern/shiny/Main/ShaderSet.hpp +++ b/extern/shiny/Main/ShaderSet.hpp @@ -30,9 +30,6 @@ namespace sh /// so it does not matter if you pass any extra properties that the shader does not care about. ShaderInstance* getInstance (PropertySetGet* properties); - void markDirty() { mIsDirty = true; } - ///< Signals that the cache is out of date, and thus should not be used this time - private: PropertySetGet* getCurrentGlobalSettings() const; std::string getBasePath() const; @@ -41,12 +38,8 @@ namespace sh std::string getHlslProfile() const; int getType() const; - bool isDirty() { return mIsDirty; } - friend class ShaderInstance; - bool mIsDirty; - private: GpuProgramType mType; std::string mSource; From bec538bfa155717b04287aed98c4e6b86b99a73c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 09:19:59 -0800 Subject: [PATCH 514/916] Always declare operator<< for using a TextKeyMap with Ogre::Any --- components/nifogre/ogre_nif_loader.cpp | 3 --- components/nifogre/ogre_nif_loader.hpp | 10 ++++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8175279d0..b878c29f4 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -54,9 +54,6 @@ typedef unsigned char ubyte; namespace std { -// These operators allow extra data types to be stored in an Ogre::Any -// object, which can then be stored in user object bindings on the nodes - // TODO: Do something useful ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) { return o; } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 13a76d472..12be52233 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -81,4 +81,14 @@ public: } +namespace std +{ + +// These operators allow extra data types to be stored in an Ogre::Any +// object, which can then be stored in user object bindings on the nodes + +ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&); + +} + #endif From 6b32fa7999b3bd6f0341cef088b616b547395907 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 09:48:21 -0800 Subject: [PATCH 515/916] Use the correct position for the actor --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7962e197e..29ea723ed 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -183,7 +183,7 @@ Ogre::Vector3 CharacterController::update(float duration) if(duration > 0.0f) { - Ogre::Vector3 pos(mPtr.getCellRef().mPos.pos); + Ogre::Vector3 pos(mPtr.getRefData().getPosition().pos); // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); From e94976592256a70d76218753992b77a02eeecd99 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Feb 2013 19:21:47 +0100 Subject: [PATCH 516/916] cloud blending now as before (0 -> 0.25 -> 1) --- files/materials/clouds.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index 9126ae423..4b1868fb4 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -14,7 +14,7 @@ { shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; - alphaFade = shInputPosition.z < 100.f ? 0 : 1; + alphaFade = (shInputPosition.z <= 200.f) ? ((shInputPosition.z <= 100.f) ? 0.0 : 0.25) : 1.0; } #else From 1a5cb8760d6047ee57cb2b4333248ece3cad9d09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 11:04:20 -0800 Subject: [PATCH 517/916] Rotate movement vector to world space before passing to the movement solver --- apps/openmw/mwmechanics/character.cpp | 11 ++++++++++- apps/openmw/mwmechanics/movementsolver.cpp | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 29ea723ed..8eb0caf58 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -183,7 +183,16 @@ Ogre::Vector3 CharacterController::update(float duration) if(duration > 0.0f) { - Ogre::Vector3 pos(mPtr.getRefData().getPosition().pos); + const ESM::Position &refpos = mPtr.getRefData().getPosition(); + + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; + + Ogre::Vector3 pos(refpos.pos); + // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 219f077e4..a758c76f3 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -9,6 +9,7 @@ namespace MWMechanics MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) : mPtr(ptr) , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) + , verticalVelocity(0.0f) { } @@ -71,11 +72,10 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) { - mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); - /* Anything to collide with? */ - if(1 || !mPhysicActor || !mPhysicActor->getCollisionMode()) - return position+movement; + mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + if(!mPhysicActor || !mPhysicActor->getCollisionMode()) + return position + movement; traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. From 39cf7b0b42f32e98e9cb2864eb7361d30a4ad979 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 11:17:48 -0800 Subject: [PATCH 518/916] Pass the Ptr of the object being moved to the move method This prevents having to store another copy of it, which risks getting out of sync. --- apps/openmw/mwmechanics/character.cpp | 8 +++----- apps/openmw/mwmechanics/movementsolver.cpp | 20 ++++++++++++++------ apps/openmw/mwmechanics/movementsolver.hpp | 22 +++++++++++++++------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8eb0caf58..b98a863ae 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -79,7 +79,7 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { - mMovementSolver = new MovementSolver(mPtr); + mMovementSolver = new MovementSolver(); if(!mAnimation) return; @@ -98,7 +98,7 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { - mMovementSolver = new MovementSolver(mPtr); + mMovementSolver = new MovementSolver(); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ @@ -191,10 +191,8 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * movement; - Ogre::Vector3 pos(refpos.pos); - // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? - Ogre::Vector3 res = mMovementSolver->move(pos, movement, duration, Ogre::Vector3(15,15,30)); + Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration, Ogre::Vector3(15,15,30)); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); } diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index a758c76f3..4a7a59cb3 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -1,14 +1,20 @@ #include "movementsolver.hpp" +#include "libs/openengine/bullet/trace.h" +#include "libs/openengine/bullet/physic.hpp" + +#include "../mwworld/ptr.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include + + namespace MWMechanics { -MovementSolver::MovementSolver(const MWWorld::Ptr &ptr) - : mPtr(ptr) - , mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) +MovementSolver::MovementSolver() + : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) , verticalVelocity(0.0f) { } @@ -70,10 +76,12 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) } -Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) { + Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + /* Anything to collide with? */ - mPhysicActor = mEngine->getCharacter(mPtr.getRefData().getHandle()); + mPhysicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); if(!mPhysicActor || !mPhysicActor->getCollisionMode()) return position + movement; @@ -86,7 +94,7 @@ Ogre::Vector3 MovementSolver::move(const Ogre::Vector3 &position, const Ogre::Ve Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); float remainingTime = time; - bool isInterior = !mPtr.getCell()->isExterior(); + bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 lastNormal(0.0f); diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 8bd05fa15..450bc055e 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -1,22 +1,31 @@ #ifndef GAME_MWMECHANICS_MOVEMENTSOLVER_H #define GAME_MWMECHANICS_MOVEMENTSOLVER_H -#include "libs/openengine/bullet/trace.h" -#include "libs/openengine/bullet/physic.hpp" +#include -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; +} -#include +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + class PhysicActor; + } +} namespace MWMechanics { class MovementSolver { public: - MovementSolver(const MWWorld::Ptr &ptr); + MovementSolver(); virtual ~MovementSolver(); - Ogre::Vector3 move(const Ogre::Vector3 &position, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); private: bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); @@ -26,7 +35,6 @@ namespace MWMechanics float getSlope(const Ogre::Vector3 &normal); - MWWorld::Ptr mPtr; OEngine::Physic::PhysicEngine *mEngine; OEngine::Physic::PhysicActor *mPhysicActor; From ee9b19d2ed92c1d9bdb03f9216d398cb42b1fb03 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 12:04:06 -0800 Subject: [PATCH 519/916] Make sure to remove a Ptr from the activators when requested --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 9e76084f5..085cb6653 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -188,6 +188,7 @@ namespace MWMechanics if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); + mActivators.removeActivator(ptr); } void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) From 2f8affc95507e5f7264a91da06e5ff440e9b0c21 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 12:58:06 -0800 Subject: [PATCH 520/916] Make sure the player's controller is properly updated when they change --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 085cb6653..eee72f880 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -309,6 +309,12 @@ namespace MWMechanics } winMgr->configureSkills (majorSkills, minorSkills); + + // HACK? The player has been changed, so a new Animation object may + // have been made for them. Make sure they're properly updated. + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + mActors.removeActor(ptr); + mActors.addActor(ptr); } mActors.update(duration, paused); From 66ec4ca7d9e8cd9abaea4dbee0a3b345ae66cabb Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Mon, 4 Feb 2013 22:14:14 +0100 Subject: [PATCH 521/916] Split launcher specific code from DataFilesList back to DataFilesPage. --- apps/launcher/CMakeLists.txt | 9 + apps/launcher/datafilespage.cpp | 533 +++++++++++++++++ apps/launcher/datafilespage.hpp | 80 +++ apps/launcher/maindialog.cpp | 21 +- apps/launcher/maindialog.hpp | 4 +- .../launcher}/utils/profilescombobox.cpp | 0 .../launcher}/utils/profilescombobox.hpp | 0 .../launcher}/utils/textinputdialog.cpp | 0 .../launcher}/utils/textinputdialog.hpp | 0 apps/opencs/view/doc/opendialog.cpp | 39 +- components/CMakeLists.txt | 2 +- components/fileorderlist/datafileslist.cpp | 563 +----------------- components/fileorderlist/datafileslist.hpp | 31 +- 13 files changed, 706 insertions(+), 576 deletions(-) create mode 100644 apps/launcher/datafilespage.cpp create mode 100644 apps/launcher/datafilespage.hpp rename {components/fileorderlist => apps/launcher}/utils/profilescombobox.cpp (100%) rename {components/fileorderlist => apps/launcher}/utils/profilescombobox.hpp (100%) rename {components/fileorderlist => apps/launcher}/utils/textinputdialog.cpp (100%) rename {components/fileorderlist => apps/launcher}/utils/textinputdialog.hpp (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 73efb9ee5..ce0649cd6 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -3,6 +3,9 @@ set(LAUNCHER main.cpp maindialog.cpp playpage.cpp + datafilespage.cpp + utils/profilescombobox.cpp + utils/textinputdialog.cpp launcher.rc ) @@ -11,6 +14,9 @@ set(LAUNCHER_HEADER graphicspage.hpp maindialog.hpp playpage.hpp + datafilespage.hpp + utils/profilescombobox.hpp + utils/textinputdialog.hpp ) # Headers that must be pre-processed @@ -18,6 +24,9 @@ set(LAUNCHER_HEADER_MOC graphicspage.hpp maindialog.hpp playpage.hpp + datafilespage.hpp + utils/profilescombobox.hpp + utils/textinputdialog.hpp ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp new file mode 100644 index 000000000..52b8c9cbe --- /dev/null +++ b/apps/launcher/datafilespage.cpp @@ -0,0 +1,533 @@ +#include + +#include +#include +#include +#include +#include +#include + +////#include "model/datafilesmodel.hpp" +////#include "model/esm/esmfile.hpp" + +#include "utils/profilescombobox.hpp" +////#include "utils/filedialog.hpp" +////#include "utils/naturalsort.hpp" +#include "utils/textinputdialog.hpp" + +#include "datafilespage.hpp" + +#include +/** + * Workaround for problems with whitespaces in paths in older versions of Boost library + */ +#if (BOOST_VERSION <= 104600) +namespace boost +{ + + template<> + inline boost::filesystem::path lexical_cast(const std::string& arg) + { + return boost::filesystem::path(arg); + } + +} /* namespace boost */ +#endif /* (BOOST_VERSION <= 104600) */ + +using namespace ESM; +using namespace std; + +DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) + : QWidget(parent) + , mCfgMgr(cfg) +{ + mDataFilesList = new DataFilesList(mCfgMgr, this); + + // Bottom part with profile options + QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); + + mProfilesComboBox = new ProfilesComboBox(this); + mProfilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); + mProfilesComboBox->setInsertPolicy(QComboBox::NoInsert); + mProfilesComboBox->setDuplicatesEnabled(false); + mProfilesComboBox->setEditEnabled(false); + + mProfileToolBar = new QToolBar(this); + mProfileToolBar->setMovable(false); + mProfileToolBar->setIconSize(QSize(16, 16)); + + mProfileToolBar->addWidget(profileLabel); + mProfileToolBar->addWidget(mProfilesComboBox); + + QVBoxLayout *pageLayout = new QVBoxLayout(this); + + pageLayout->addWidget(mDataFilesList); + pageLayout->addWidget(mProfileToolBar); + + // Create a dialog for the new profile name input + mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + + connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); + + connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); + connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); + + createActions(); + setupConfig(); +} + +void DataFilesPage::createActions() +{ + // Refresh the plugins + QAction *refreshAction = new QAction(tr("Refresh"), this); + refreshAction->setShortcut(QKeySequence(tr("F5"))); + connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); + + // Profile actions + mNewProfileAction = new QAction(QIcon::fromTheme("document-new"), tr("&New Profile"), this); + mNewProfileAction->setToolTip(tr("New Profile")); + mNewProfileAction->setShortcut(QKeySequence(tr("Ctrl+N"))); + connect(mNewProfileAction, SIGNAL(triggered()), this, SLOT(newProfile())); + + mDeleteProfileAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete Profile"), this); + mDeleteProfileAction->setToolTip(tr("Delete Profile")); + mDeleteProfileAction->setShortcut(QKeySequence(tr("Delete"))); + connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); + + // Add the newly created actions to the toolbar + mProfileToolBar->addSeparator(); + mProfileToolBar->addAction(mNewProfileAction); + mProfileToolBar->addAction(mDeleteProfileAction); +} + +void DataFilesPage::setupConfig() +{ + // Open our config file + QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); + mLauncherConfig = new QSettings(config, QSettings::IniFormat); + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + QStringList profiles = mLauncherConfig->childGroups(); + + // Add the profiles to the combobox + foreach (const QString &profile, profiles) { + + if (profile.contains(QRegExp("[^a-zA-Z0-9_]"))) + continue; // Profile name contains garbage + + + qDebug() << "adding " << profile; + mProfilesComboBox->addItem(profile); + } + + // Add a default profile + if (mProfilesComboBox->findText(QString("Default")) == -1) { + mProfilesComboBox->addItem(QString("Default")); + } + + QString currentProfile = mLauncherConfig->value("CurrentProfile").toString(); + + if (currentProfile.isEmpty()) { + // No current profile selected + currentProfile = "Default"; + } + + const int currentIndex = mProfilesComboBox->findText(currentProfile); + if (currentIndex != -1) { + // Profile is found + mProfilesComboBox->setCurrentIndex(currentIndex); + } + + mLauncherConfig->endGroup(); +} + + +void DataFilesPage::readConfig() +{ + QString profile = mProfilesComboBox->currentText(); + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + mLauncherConfig->beginGroup(profile); + + QStringList childKeys = mLauncherConfig->childKeys(); + QStringList plugins; + + // Sort the child keys numerical instead of alphabetically + // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 + qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); + + foreach (const QString &key, childKeys) { + const QString keyValue = mLauncherConfig->value(key).toString(); + + mDataFilesList->setCheckState(keyValue, Qt::Checked); + } + + qDebug() << plugins; +} + +bool DataFilesPage::showDataFilesWarning() +{ + + QMessageBox msgBox; + msgBox.setWindowTitle("Error detecting Morrowind installation"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(tr("
Could not find the Data Files location

\ + The directory containing the data files was not found.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + if (msgBox.clickedButton() == dirSelectButton) { + + // Show a custom dir selection dialog which only accepts valid dirs + QString selectedDir = FileDialog::getExistingDirectory( + this, tr("Select Data Files Directory"), + QDir::currentPath(), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + // Add the user selected data directory + if (!selectedDir.isEmpty()) { + mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); + mCfgMgr.processPaths(mDataDirs); + } else { + // Cancel from within the dir selection dialog + return false; + } + + } else { + // Cancel + return false; + } + + return true; +} + +bool DataFilesPage::setupDataFiles() +{ + // We use the Configuration Manager to retrieve the configuration values + boost::program_options::variables_map variables; + boost::program_options::options_description desc; + + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) + ("data-local", boost::program_options::value()->default_value("")) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("encoding", boost::program_options::value()->default_value("win1252")); + + boost::program_options::notify(variables); + + mCfgMgr.readConfiguration(variables, desc); + + if (variables["data"].empty()) { + if (!showDataFilesWarning()) + return false; + } else { + mDataDirs = Files::PathContainer(variables["data"].as()); + } + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + mDataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + // Second chance to display the warning, the data= entries are invalid + while (mDataDirs.empty()) { + if (!showDataFilesWarning()) + return false; + } + + // Set the charset for reading the esm/esp files + QString encoding = QString::fromStdString(variables["encoding"].as()); + + Files::PathContainer paths; + paths.insert(paths.end(), mDataDirs.begin(), mDataDirs.end()); + paths.insert(paths.end(), mDataLocal.begin(), mDataLocal.end()); + mDataFilesList->setupDataFiles(paths, encoding); + readConfig(); + return true; +} + +void DataFilesPage::writeConfig(QString profile) +{ + QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); + QDir userPath(pathStr); + + if (!userPath.exists()) { + if (!userPath.mkpath(pathStr)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error creating OpenMW configuration directory"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not create %0

\ + Please make sure you have the right permissions and try again.
").arg(pathStr)); + msgBox.exec(); + + qApp->quit(); + return; + } + } + // Open the OpenMW config as a QFile + QFile file(pathStr.append("openmw.cfg")); + + if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0

\ + Please make sure you have the right permissions and try again.
").arg(file.fileName())); + msgBox.exec(); + + qApp->quit(); + return; + } + + QTextStream in(&file); + QByteArray buffer; + + // Remove all previous entries from config + while (!in.atEnd()) { + QString line = in.readLine(); + if (!line.startsWith("master") && + !line.startsWith("plugin") && + !line.startsWith("data") && + !line.startsWith("data-local")) + { + buffer += line += "\n"; + } + } + + file.close(); + + // Now we write back the other config entries + if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not write to %0

\ + Please make sure you have the right permissions and try again.
").arg(file.fileName())); + msgBox.exec(); + + qApp->quit(); + return; + } + + if (!buffer.isEmpty()) { + file.write(buffer); + } + + QTextStream gameConfig(&file); + + // First write the list of data dirs + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + QString path; + + // data= directories + for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { + path = QString::fromStdString(it->string()); + path.remove(QChar('\"')); + + // Make sure the string is quoted when it contains spaces + if (path.contains(" ")) { + gameConfig << "data=\"" << path << "\"" << endl; + } else { + gameConfig << "data=" << path << endl; + } + } + + // data-local directory + if (!mDataLocal.empty()) { + path = QString::fromStdString(mDataLocal.front().string()); + path.remove(QChar('\"')); + + if (path.contains(" ")) { + gameConfig << "data-local=\"" << path << "\"" << endl; + } else { + gameConfig << "data-local=" << path << endl; + } + } + + + if (profile.isEmpty()) + profile = mProfilesComboBox->currentText(); + + if (profile.isEmpty()) + return; + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + mLauncherConfig->setValue("CurrentProfile", profile); + + // Open the profile-name subgroup + mLauncherConfig->beginGroup(profile); + mLauncherConfig->remove(""); // Clear the subgroup + + // Now write the masters to the configs + const QStringList checkedFiles = mDataFilesList->checkedFiles(); + for(int i=0; i < checkedFiles.size(); i++) + { + if (checkedFiles.at(i).lastIndexOf("esm") != -1) + { + mLauncherConfig->setValue(QString("Master%0").arg(i), checkedFiles.at(i)); + gameConfig << "master=" << checkedFiles.at(i) << endl; + } + else + { + mLauncherConfig->setValue(QString("Plugin%1").arg(i), checkedFiles.at(i)); + gameConfig << "plugin=" << checkedFiles.at(i) << endl; + } + } + + file.close(); + mLauncherConfig->endGroup(); + mLauncherConfig->endGroup(); + mLauncherConfig->sync(); +} + + +void DataFilesPage::newProfile() +{ + if (mNewProfileDialog->exec() == QDialog::Accepted) { + + const QString text = mNewProfileDialog->lineEdit()->text(); + mProfilesComboBox->addItem(text); + + // Copy the currently checked items to cfg + writeConfig(text); + mLauncherConfig->sync(); + + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); + } +} + +void DataFilesPage::updateOkButton(const QString &text) +{ + if (text.isEmpty()) { + mNewProfileDialog->setOkButtonEnabled(false); + return; + } + + (mProfilesComboBox->findText(text) == -1) + ? mNewProfileDialog->setOkButtonEnabled(true) + : mNewProfileDialog->setOkButtonEnabled(false); +} + +void DataFilesPage::deleteProfile() +{ + QString profile = mProfilesComboBox->currentText(); + + if (profile.isEmpty()) + return; + + QMessageBox msgBox(this); + msgBox.setWindowTitle(tr("Delete Profile")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(tr("Are you sure you want to delete %0?").arg(profile)); + + QAbstractButton *deleteButton = + msgBox.addButton(tr("Delete"), QMessageBox::ActionRole); + + msgBox.exec(); + + if (msgBox.clickedButton() == deleteButton) { + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + + // Open the profile-name subgroup + mLauncherConfig->beginGroup(profile); + mLauncherConfig->remove(""); // Clear the subgroup + mLauncherConfig->endGroup(); + mLauncherConfig->endGroup(); + + // Remove the profile from the combobox + mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); + } +} + +void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) +{ + qDebug() << "Profile is changed from: " << previous << " to " << current; + // Prevent the deletion of the default profile + if (current == QLatin1String("Default")) { + mDeleteProfileAction->setEnabled(false); + mProfilesComboBox->setEditEnabled(false); + } else { + mDeleteProfileAction->setEnabled(true); + mProfilesComboBox->setEditEnabled(true); + } + + if (!previous.isEmpty()) { + writeConfig(previous); + mLauncherConfig->sync(); + + if (mProfilesComboBox->currentIndex() == -1) + return; + + } else { + return; + } + + mDataFilesList->uncheckAll(); + readConfig(); +} + +void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) +{ + if (previous.isEmpty()) + return; + + // Save the new profile name + writeConfig(current); + + // Make sure we have no groups open + while (!mLauncherConfig->group().isEmpty()) { + mLauncherConfig->endGroup(); + } + + mLauncherConfig->beginGroup("Profiles"); + + // Open the profile-name subgroup + mLauncherConfig->beginGroup(previous); + mLauncherConfig->remove(""); // Clear the subgroup + mLauncherConfig->endGroup(); + mLauncherConfig->endGroup(); + mLauncherConfig->sync(); + + // Remove the profile from the combobox + mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); + + mDataFilesList->uncheckAll(); + ////mMastersModel->uncheckAll(); + ////mPluginsModel->uncheckAll(); + readConfig(); +} diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp new file mode 100644 index 000000000..0584de436 --- /dev/null +++ b/apps/launcher/datafilespage.hpp @@ -0,0 +1,80 @@ +#ifndef DATAFILESPAGE_H +#define DATAFILESPAGE_H + +#include +#include +#include "utils/profilescombobox.hpp" +#include + + +class QTableView; +class QSortFilterProxyModel; +class QSettings; +class QAction; +class QToolBar; +class QMenu; +class ProfilesComboBox; +class DataFilesModel; + +class TextInputDialog; +class DataFilesList; + +namespace Files { struct ConfigurationManager; } + +class DataFilesPage : public QWidget +{ + Q_OBJECT + +public: + DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); + + ProfilesComboBox *mProfilesComboBox; + + void writeConfig(QString profile = QString()); + bool showDataFilesWarning(); + bool setupDataFiles(); + +public slots: + void profileChanged(const QString &previous, const QString ¤t); + void profileRenamed(const QString &previous, const QString ¤t); + void updateOkButton(const QString &text); + + // Action slots + void newProfile(); + void deleteProfile(); +// void moveUp(); +// void moveDown(); +// void moveTop(); +// void moveBottom(); + +private: + DataFilesList *mDataFilesList; + + QToolBar *mProfileToolBar; + + QAction *mNewProfileAction; + QAction *mDeleteProfileAction; + +// QAction *mMoveUpAction; +// QAction *mMoveDownAction; +// QAction *mMoveTopAction; +// QAction *mMoveBottomAction; + + Files::ConfigurationManager &mCfgMgr; + Files::PathContainer mDataDirs; + Files::PathContainer mDataLocal; + + QSettings *mLauncherConfig; + + TextInputDialog *mNewProfileDialog; + +// const QStringList checkedPlugins(); +// const QStringList selectedMasters(); + + void createActions(); + void setupConfig(); + void readConfig(); + +}; + +#endif diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 7914650fe..674ccdf67 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,10 +1,9 @@ #include -#include - #include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" +#include "datafilespage.hpp" MainDialog::MainDialog() { @@ -124,16 +123,16 @@ void MainDialog::createPages() { mPlayPage = new PlayPage(this); mGraphicsPage = new GraphicsPage(mCfgMgr, this); - mDataFilesList = new DataFilesList(mCfgMgr, this); + mDataFilesPage = new DataFilesPage(mCfgMgr, this); // Set the combobox of the play page to imitate the combobox on the datafilespage - mPlayPage->mProfilesComboBox->setModel(mDataFilesList->mProfilesComboBox->model()); - mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesList->mProfilesComboBox->currentIndex()); + mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); + mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget mPagesWidget->addWidget(mPlayPage); mPagesWidget->addWidget(mGraphicsPage); - mPagesWidget->addWidget(mDataFilesList); + mPagesWidget->addWidget(mDataFilesPage); // Select the first page mIconWidget->setCurrentItem(mIconWidget->item(0), QItemSelectionModel::Select); @@ -142,9 +141,9 @@ void MainDialog::createPages() connect(mPlayPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), - mDataFilesList->mProfilesComboBox, SLOT(setCurrentIndex(int))); + mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); - connect(mDataFilesList->mProfilesComboBox, + connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); @@ -190,7 +189,7 @@ bool MainDialog::setup() } // Setup the Data Files page - if (!mDataFilesList->setupDataFiles()) { + if (!mDataFilesPage->setupDataFiles()) { return false; } @@ -208,7 +207,7 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) void MainDialog::closeEvent(QCloseEvent *event) { // Now write all config files - mDataFilesList->writeConfig(); + mDataFilesPage->writeConfig(); mGraphicsPage->writeConfig(); // Save user settings @@ -221,7 +220,7 @@ void MainDialog::closeEvent(QCloseEvent *event) void MainDialog::play() { // First do a write of all the configs, just to be sure - mDataFilesList->writeConfig(); + mDataFilesPage->writeConfig(); mGraphicsPage->writeConfig(); // Save user settings diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 5a39c11a9..bf98011cc 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -15,7 +15,7 @@ class QString; class PlayPage; class GraphicsPage; -class DataFilesList; +class DataFilesPage; class MainDialog : public QMainWindow { @@ -39,7 +39,7 @@ private: PlayPage *mPlayPage; GraphicsPage *mGraphicsPage; - DataFilesList *mDataFilesList; + DataFilesPage *mDataFilesPage; Files::ConfigurationManager mCfgMgr; Settings::Manager mSettings; diff --git a/components/fileorderlist/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp similarity index 100% rename from components/fileorderlist/utils/profilescombobox.cpp rename to apps/launcher/utils/profilescombobox.cpp diff --git a/components/fileorderlist/utils/profilescombobox.hpp b/apps/launcher/utils/profilescombobox.hpp similarity index 100% rename from components/fileorderlist/utils/profilescombobox.hpp rename to apps/launcher/utils/profilescombobox.hpp diff --git a/components/fileorderlist/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp similarity index 100% rename from components/fileorderlist/utils/textinputdialog.cpp rename to apps/launcher/utils/textinputdialog.cpp diff --git a/components/fileorderlist/utils/textinputdialog.hpp b/apps/launcher/utils/textinputdialog.hpp similarity index 100% rename from components/fileorderlist/utils/textinputdialog.hpp rename to apps/launcher/utils/textinputdialog.hpp diff --git a/apps/opencs/view/doc/opendialog.cpp b/apps/opencs/view/doc/opendialog.cpp index f51cbadb9..9a5feb23a 100644 --- a/apps/opencs/view/doc/opendialog.cpp +++ b/apps/opencs/view/doc/opendialog.cpp @@ -10,7 +10,42 @@ OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) QVBoxLayout *layout = new QVBoxLayout(this); mFileSelector = new DataFilesList(mCfgMgr, this); layout->addWidget(mFileSelector); - mFileSelector->setupDataFiles(); + + //FIXME - same as DataFilesPage::setupDataFiles + // We use the Configuration Manager to retrieve the configuration values + boost::program_options::variables_map variables; + boost::program_options::options_description desc; + + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) + ("data-local", boost::program_options::value()->default_value("")) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("encoding", boost::program_options::value()->default_value("win1252")); + + boost::program_options::notify(variables); + + mCfgMgr.readConfiguration(variables, desc); + + Files::PathContainer mDataDirs, mDataLocal; + if (!variables["data"].empty()) { + mDataDirs = Files::PathContainer(variables["data"].as()); + } + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + mDataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + // Set the charset for reading the esm/esp files + QString encoding = QString::fromStdString(variables["encoding"].as()); + + Files::PathContainer dataDirs; + dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end()); + dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end()); + mFileSelector->setupDataFiles(dataDirs, encoding); buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); @@ -23,5 +58,5 @@ OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) void OpenDialog::getFileList(std::vector& paths) { - mFileSelector->getSelectedFiles(paths); + mFileSelector->selectedFiles(paths); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 63a227621..00342e2ac 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -71,7 +71,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui) if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (fileorderlist datafileslist model/modelitem model/datafilesmodel model/esm/esmfile - utils/filedialog utils/lineedit utils/profilescombobox utils/textinputdialog utils/naturalsort + utils/filedialog utils/lineedit utils/naturalsort ) include(${QT_USE_FILE}) diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index f346407a9..38e0bfb1a 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -6,11 +6,9 @@ #include "model/datafilesmodel.hpp" #include "model/esm/esmfile.hpp" -#include "utils/profilescombobox.hpp" #include "utils/filedialog.hpp" #include "utils/lineedit.hpp" #include "utils/naturalsort.hpp" -#include "utils/textinputdialog.hpp" #include "datafileslist.hpp" @@ -137,32 +135,10 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) sizeList << 175 << 200; splitter->setSizes(sizeList); - // Bottom part with profile options - QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); - - mProfilesComboBox = new ProfilesComboBox(this); - mProfilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); - mProfilesComboBox->setInsertPolicy(QComboBox::NoInsert); - mProfilesComboBox->setDuplicatesEnabled(false); - mProfilesComboBox->setEditEnabled(false); - - mProfileToolBar = new QToolBar(this); - mProfileToolBar->setMovable(false); - mProfileToolBar->setIconSize(QSize(16, 16)); - - mProfileToolBar->addWidget(profileLabel); - mProfileToolBar->addWidget(mProfilesComboBox); - QVBoxLayout *pageLayout = new QVBoxLayout(this); pageLayout->addWidget(filterToolBar); pageLayout->addWidget(splitter); - pageLayout->addWidget(mProfileToolBar); - - // Create a dialog for the new profile name input - mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); - - connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); @@ -173,11 +149,7 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); - connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); - createActions(); - setupConfig(); } void DataFilesList::createActions() @@ -187,22 +159,6 @@ void DataFilesList::createActions() refreshAction->setShortcut(QKeySequence(tr("F5"))); connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); - // Profile actions - mNewProfileAction = new QAction(QIcon::fromTheme("document-new"), tr("&New Profile"), this); - mNewProfileAction->setToolTip(tr("New Profile")); - mNewProfileAction->setShortcut(QKeySequence(tr("Ctrl+N"))); - connect(mNewProfileAction, SIGNAL(triggered()), this, SLOT(newProfile())); - - mDeleteProfileAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete Profile"), this); - mDeleteProfileAction->setToolTip(tr("Delete Profile")); - mDeleteProfileAction->setShortcut(QKeySequence(tr("Delete"))); - connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); - - // Add the newly created actions to the toolbar - mProfileToolBar->addSeparator(); - mProfileToolBar->addAction(mNewProfileAction); - mProfileToolBar->addAction(mDeleteProfileAction); - // Context menu actions mCheckAction = new QAction(tr("Check selected"), this); connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check())); @@ -218,223 +174,16 @@ void DataFilesList::createActions() } -void DataFilesList::setupConfig() +bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString encoding) { - // Open our config file - QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); - mLauncherConfig = new QSettings(config, QSettings::IniFormat); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - QStringList profiles = mLauncherConfig->childGroups(); - - // Add the profiles to the combobox - foreach (const QString &profile, profiles) { - - if (profile.contains(QRegExp("[^a-zA-Z0-9_]"))) - continue; // Profile name contains garbage - - - qDebug() << "adding " << profile; - mProfilesComboBox->addItem(profile); - } - - // Add a default profile - if (mProfilesComboBox->findText(QString("Default")) == -1) { - mProfilesComboBox->addItem(QString("Default")); - } - - QString currentProfile = mLauncherConfig->value("CurrentProfile").toString(); - - if (currentProfile.isEmpty()) { - // No current profile selected - currentProfile = "Default"; - } - - const int currentIndex = mProfilesComboBox->findText(currentProfile); - if (currentIndex != -1) { - // Profile is found - mProfilesComboBox->setCurrentIndex(currentIndex); - } - - mLauncherConfig->endGroup(); -} - - -void DataFilesList::readConfig() -{ - // Don't read the config if no masters are found - if (mMastersModel->rowCount() < 1) - return; - - QString profile = mProfilesComboBox->currentText(); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - mLauncherConfig->beginGroup(profile); - - QStringList childKeys = mLauncherConfig->childKeys(); - QStringList plugins; - - // Sort the child keys numerical instead of alphabetically - // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 - qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); - - foreach (const QString &key, childKeys) { - const QString keyValue = mLauncherConfig->value(key).toString(); - - if (key.startsWith("Plugin")) { - //QStringList checked = mPluginsModel->checkedItems(); - EsmFile *file = mPluginsModel->findItem(keyValue); - QModelIndex index = mPluginsModel->indexFromItem(file); - - mPluginsModel->setCheckState(index, Qt::Checked); - // Move the row to the top of te view - //mPluginsModel->moveRow(index.row(), checked.count()); - plugins << keyValue; - } - - if (key.startsWith("Master")) { - EsmFile *file = mMastersModel->findItem(keyValue); - mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); - } - } - - qDebug() << plugins; - - -// // Set the checked item positions -// const QStringList checked = mPluginsModel->checkedItems(); -// for (int i = 0; i < plugins.size(); ++i) { -// EsmFile *file = mPluginsModel->findItem(plugins.at(i)); -// QModelIndex index = mPluginsModel->indexFromItem(file); -// mPluginsModel->moveRow(index.row(), i); -// qDebug() << "Moving: " << plugins.at(i) << " from: " << index.row() << " to: " << i << " count: " << checked.count(); - -// } - - // Iterate over the plugins to set their checkstate and position -// for (int i = 0; i < plugins.size(); ++i) { -// const QString plugin = plugins.at(i); - -// const QList pluginList = mPluginsModel->findItems(plugin); - -// if (!pluginList.isEmpty()) -// { -// foreach (const QStandardItem *currentPlugin, pluginList) { -// mPluginsModel->setData(currentPlugin->index(), Qt::Checked, Qt::CheckStateRole); - -// // Move the plugin to the position specified in the config file -// mPluginsModel->insertRow(i, mPluginsModel->takeRow(currentPlugin->row())); -// } -// } -// } - -} - -bool DataFilesList::showDataFilesWarning() -{ - - QMessageBox msgBox; - msgBox.setWindowTitle("Error detecting Morrowind installation"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("
Could not find the Data Files location

\ - The directory containing the data files was not found.

\ - Press \"Browse...\" to specify the location manually.
")); - - QAbstractButton *dirSelectButton = - msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); - - msgBox.exec(); - - if (msgBox.clickedButton() == dirSelectButton) { - - // Show a custom dir selection dialog which only accepts valid dirs - QString selectedDir = FileDialog::getExistingDirectory( - this, tr("Select Data Files Directory"), - QDir::currentPath(), - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - - // Add the user selected data directory - if (!selectedDir.isEmpty()) { - mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); - mCfgMgr.processPaths(mDataDirs); - } else { - // Cancel from within the dir selection dialog - return false; - } - - } else { - // Cancel - return false; - } - - return true; -} - -bool DataFilesList::setupDataFiles() -{ - // We use the Configuration Manager to retrieve the configuration values - boost::program_options::variables_map variables; - boost::program_options::options_description desc; - - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) - ("data-local", boost::program_options::value()->default_value("")) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("encoding", boost::program_options::value()->default_value("win1252")); - - boost::program_options::notify(variables); - - mCfgMgr.readConfiguration(variables, desc); - - if (variables["data"].empty()) { - if (!showDataFilesWarning()) - return false; - } else { - mDataDirs = Files::PathContainer(variables["data"].as()); - } - - std::string local = variables["data-local"].as(); - if (!local.empty()) { - mDataLocal.push_back(Files::PathContainer::value_type(local)); - } - - mCfgMgr.processPaths(mDataDirs); - mCfgMgr.processPaths(mDataLocal); - - // Second chance to display the warning, the data= entries are invalid - while (mDataDirs.empty()) { - if (!showDataFilesWarning()) - return false; - } - // Set the charset for reading the esm/esp files - QString encoding = QString::fromStdString(variables["encoding"].as()); if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { mMastersModel->setEncoding(encoding); mPluginsModel->setEncoding(encoding); } // Add the paths to the respective models - for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { - QString path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - mMastersModel->addMasters(path); - mPluginsModel->addPlugins(path); - } - - // Same for the data-local paths - for (Files::PathContainer::iterator it = mDataLocal.begin(); it != mDataLocal.end(); ++it) { + for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { QString path = QString::fromStdString(it->string()); path.remove(QChar('\"')); mMastersModel->addMasters(path); @@ -446,12 +195,10 @@ bool DataFilesList::setupDataFiles() // mMastersTable->sortByColumn(3, Qt::AscendingOrder); // mPluginsTable->sortByColumn(3, Qt::AscendingOrder); - - readConfig(); return true; } -void DataFilesList::getSelectedFiles(std::vector& paths) +void DataFilesList::selectedFiles(std::vector& paths) { QStringList masterPaths = mMastersModel->checkedItemsPaths(); foreach (const QString &path, masterPaths) @@ -467,225 +214,6 @@ void DataFilesList::getSelectedFiles(std::vector& paths } } -void DataFilesList::writeConfig(QString profile) -{ - // Don't overwrite the config if no masters are found - if (mMastersModel->rowCount() < 1) - return; - - QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); - QDir userPath(pathStr); - - if (!userPath.exists()) { - if (!userPath.mkpath(pathStr)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error creating OpenMW configuration directory"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not create %0

\ - Please make sure you have the right permissions and try again.
").arg(pathStr)); - msgBox.exec(); - - qApp->quit(); - return; - } - } - // Open the OpenMW config as a QFile - QFile file(pathStr.append("openmw.cfg")); - - if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { - // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not open or create %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); - msgBox.exec(); - - qApp->quit(); - return; - } - - QTextStream in(&file); - QByteArray buffer; - - // Remove all previous entries from config - while (!in.atEnd()) { - QString line = in.readLine(); - if (!line.startsWith("master") && - !line.startsWith("plugin") && - !line.startsWith("data") && - !line.startsWith("data-local")) - { - buffer += line += "\n"; - } - } - - file.close(); - - // Now we write back the other config entries - if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not write to %0

\ - Please make sure you have the right permissions and try again.
").arg(file.fileName())); - msgBox.exec(); - - qApp->quit(); - return; - } - - if (!buffer.isEmpty()) { - file.write(buffer); - } - - QTextStream gameConfig(&file); - - // First write the list of data dirs - mCfgMgr.processPaths(mDataDirs); - mCfgMgr.processPaths(mDataLocal); - - QString path; - - // data= directories - for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { - path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - - // Make sure the string is quoted when it contains spaces - if (path.contains(" ")) { - gameConfig << "data=\"" << path << "\"" << endl; - } else { - gameConfig << "data=" << path << endl; - } - } - - // data-local directory - if (!mDataLocal.empty()) { - path = QString::fromStdString(mDataLocal.front().string()); - path.remove(QChar('\"')); - - if (path.contains(" ")) { - gameConfig << "data-local=\"" << path << "\"" << endl; - } else { - gameConfig << "data-local=" << path << endl; - } - } - - - if (profile.isEmpty()) - profile = mProfilesComboBox->currentText(); - - if (profile.isEmpty()) - return; - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - mLauncherConfig->setValue("CurrentProfile", profile); - - // Open the profile-name subgroup - mLauncherConfig->beginGroup(profile); - mLauncherConfig->remove(""); // Clear the subgroup - - // Now write the masters to the configs - const QStringList masters = mMastersModel->checkedItems(); - - // We don't use foreach because we need i - for (int i = 0; i < masters.size(); ++i) { - const QString currentMaster = masters.at(i); - - mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster); - gameConfig << "master=" << currentMaster << endl; - - } - - // And finally write all checked plugins - const QStringList plugins = mPluginsModel->checkedItems(); - - for (int i = 0; i < plugins.size(); ++i) { - const QString currentPlugin = plugins.at(i); - mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin); - gameConfig << "plugin=" << currentPlugin << endl; - } - - file.close(); - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - mLauncherConfig->sync(); -} - - -void DataFilesList::newProfile() -{ - if (mNewProfileDialog->exec() == QDialog::Accepted) { - - const QString text = mNewProfileDialog->lineEdit()->text(); - mProfilesComboBox->addItem(text); - - // Copy the currently checked items to cfg - writeConfig(text); - mLauncherConfig->sync(); - - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); - } -} - -void DataFilesList::updateOkButton(const QString &text) -{ - if (text.isEmpty()) { - mNewProfileDialog->setOkButtonEnabled(false); - return; - } - - (mProfilesComboBox->findText(text) == -1) - ? mNewProfileDialog->setOkButtonEnabled(true) - : mNewProfileDialog->setOkButtonEnabled(false); -} - -void DataFilesList::deleteProfile() -{ - QString profile = mProfilesComboBox->currentText(); - - if (profile.isEmpty()) - return; - - QMessageBox msgBox(this); - msgBox.setWindowTitle(tr("Delete Profile")); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("Are you sure you want to delete %0?").arg(profile)); - - QAbstractButton *deleteButton = - msgBox.addButton(tr("Delete"), QMessageBox::ActionRole); - - msgBox.exec(); - - if (msgBox.clickedButton() == deleteButton) { - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - - // Open the profile-name subgroup - mLauncherConfig->beginGroup(profile); - mLauncherConfig->remove(""); // Clear the subgroup - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - - // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); - } -} - void DataFilesList::check() { // Check the current selection @@ -733,8 +261,6 @@ void DataFilesList::refresh() // Refresh the plugins table mPluginsTable->scrollToTop(); - writeConfig(); - readConfig(); } @@ -767,70 +293,18 @@ void DataFilesList::setCheckState(QModelIndex index) } +void DataFilesList::uncheckAll() +{ + mMastersModel->uncheckAll(); + mPluginsModel->uncheckAll(); +} + void DataFilesList::filterChanged(const QString filter) { QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); mPluginsProxyModel->setFilterRegExp(regExp); } -void DataFilesList::profileChanged(const QString &previous, const QString ¤t) -{ - qDebug() << "Profile is changed from: " << previous << " to " << current; - // Prevent the deletion of the default profile - if (current == QLatin1String("Default")) { - mDeleteProfileAction->setEnabled(false); - mProfilesComboBox->setEditEnabled(false); - } else { - mDeleteProfileAction->setEnabled(true); - mProfilesComboBox->setEditEnabled(true); - } - - if (!previous.isEmpty()) { - writeConfig(previous); - mLauncherConfig->sync(); - - if (mProfilesComboBox->currentIndex() == -1) - return; - - } else { - return; - } - - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); - readConfig(); -} - -void DataFilesList::profileRenamed(const QString &previous, const QString ¤t) -{ - if (previous.isEmpty()) - return; - - // Save the new profile name - writeConfig(current); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - - // Open the profile-name subgroup - mLauncherConfig->beginGroup(previous); - mLauncherConfig->remove(""); // Clear the subgroup - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - mLauncherConfig->sync(); - - // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); - readConfig(); -} - void DataFilesList::showContextMenu(const QPoint &point) { // Make sure there are plugins in the view @@ -858,3 +332,22 @@ void DataFilesList::showContextMenu(const QPoint &point) // Show menu mContextMenu->exec(globalPos); } + +void DataFilesList::setCheckState(const QString& element, Qt::CheckState state) +{ + EsmFile *file = mPluginsModel->findItem(element); + if (file) + { + mPluginsModel->setCheckState(mPluginsModel->indexFromItem(file), Qt::Checked); + } + else + { + file = mMastersModel->findItem(element); + mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); + } +} + +QStringList DataFilesList::checkedFiles() +{ + return mMastersModel->checkedItems() + mPluginsModel->checkedItems(); +} \ No newline at end of file diff --git a/components/fileorderlist/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp index 7bdb5e057..4b158d316 100644 --- a/components/fileorderlist/datafileslist.hpp +++ b/components/fileorderlist/datafileslist.hpp @@ -3,7 +3,6 @@ #include #include -#include "utils/profilescombobox.hpp" #include @@ -27,25 +26,20 @@ class DataFilesList : public QWidget public: DataFilesList(Files::ConfigurationManager& cfg, QWidget *parent = 0); - ProfilesComboBox *mProfilesComboBox; - - void writeConfig(QString profile = QString()); - bool showDataFilesWarning(); - bool setupDataFiles(); - void getSelectedFiles(std::vector& paths); + bool setupDataFiles(Files::PathContainer dataDirs, const QString encoding); + void selectedFiles(std::vector& paths); + void uncheckAll(); + QStringList checkedFiles(); + void setCheckState(const QString& element, Qt::CheckState); + public slots: void setCheckState(QModelIndex index); void filterChanged(const QString filter); void showContextMenu(const QPoint &point); - void profileChanged(const QString &previous, const QString ¤t); - void profileRenamed(const QString &previous, const QString ¤t); - void updateOkButton(const QString &text); // Action slots - void newProfile(); - void deleteProfile(); // void moveUp(); // void moveDown(); // void moveTop(); @@ -63,12 +57,8 @@ private: QTableView *mMastersTable; QTableView *mPluginsTable; - QToolBar *mProfileToolBar; QMenu *mContextMenu; - QAction *mNewProfileAction; - QAction *mDeleteProfileAction; - // QAction *mMoveUpAction; // QAction *mMoveDownAction; // QAction *mMoveTopAction; @@ -77,20 +67,11 @@ private: QAction *mUncheckAction; Files::ConfigurationManager &mCfgMgr; - Files::PathContainer mDataDirs; - Files::PathContainer mDataLocal; - - QSettings *mLauncherConfig; - - TextInputDialog *mNewProfileDialog; // const QStringList checkedPlugins(); // const QStringList selectedMasters(); void createActions(); - void setupConfig(); - void readConfig(); - }; #endif From 5ee298cdc14c0f653c377fa4c676a2487e877d54 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Feb 2013 14:08:38 -0800 Subject: [PATCH 522/916] Make sure the player updates last --- apps/openmw/mwmechanics/actors.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c1f552ae4..e829d4679 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -258,14 +258,19 @@ namespace MWMechanics if(!paused) { - std::vector > movement; + PtrControllerMap::iterator player(mActors.end()); for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 vector = iter->second.update(duration); - if(vector!=Ogre::Vector3::ZERO) - movement.push_back(std::make_pair(iter->first.getRefData().getHandle(), vector)); + if(iter->first.getRefData().getHandle() == "player") + { + /* Make sure player updates last (in case a cell transition occurs) */ + player = iter; + continue; + } + iter->second.update(duration); } - MWBase::Environment::get().getWorld()->doPhysics (movement, duration); + if(player != mActors.end()) + player->second.update(duration); } } From 596628d339472e19864d7433675e1d4e146a04d2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Feb 2013 23:13:01 +0100 Subject: [PATCH 523/916] Fix terrain derived data update (bug 534, bug 544) --- apps/openmw/mwrender/terrain.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index e5a1362d7..5b24bbd45 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../mwworld/esmstore.hpp" @@ -151,6 +152,16 @@ namespace MWRender mTerrainGroup.loadTerrain(terrainX, terrainY, true); + // when loading from a heightmap, Ogre::Terrain does not update the derived data (normal map, LOD) + // synchronously, even if we supply synchronous = true parameter to loadTerrain. + // the following to be the only way to make sure derived data is ready when rendering the next frame. + while (mTerrainGroup.isDerivedDataUpdateInProgress()) + { + // we need to wait for this to finish + OGRE_THREAD_SLEEP(5); + Root::getSingleton().getWorkQueue()->processResponses(); + } + Terrain* terrain = mTerrainGroup.getTerrain(terrainX, terrainY); initTerrainBlendMaps(terrain, cellX, cellY, From 58cf182db2df6e47e8e98e35c2c49d157857c88b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 00:21:29 +0100 Subject: [PATCH 524/916] better place for syncing --- apps/openmw/mwrender/terrain.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 5b24bbd45..f4ad261c5 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -152,16 +152,6 @@ namespace MWRender mTerrainGroup.loadTerrain(terrainX, terrainY, true); - // when loading from a heightmap, Ogre::Terrain does not update the derived data (normal map, LOD) - // synchronously, even if we supply synchronous = true parameter to loadTerrain. - // the following to be the only way to make sure derived data is ready when rendering the next frame. - while (mTerrainGroup.isDerivedDataUpdateInProgress()) - { - // we need to wait for this to finish - OGRE_THREAD_SLEEP(5); - Root::getSingleton().getWorkQueue()->processResponses(); - } - Terrain* terrain = mTerrainGroup.getTerrain(terrainX, terrainY); initTerrainBlendMaps(terrain, cellX, cellY, @@ -189,6 +179,16 @@ namespace MWRender } } + // when loading from a heightmap, Ogre::Terrain does not update the derived data (normal map, LOD) + // synchronously, even if we supply synchronous = true parameter to loadTerrain. + // the following to be the only way to make sure derived data is ready when rendering the next frame. + while (mTerrainGroup.isDerivedDataUpdateInProgress()) + { + // we need to wait for this to finish + OGRE_THREAD_SLEEP(5); + Root::getSingleton().getWorkQueue()->processResponses(); + } + mTerrainGroup.freeTemporaryResources(); } From a29919d02dd08a58114c22750bc49185e7fe704a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 00:39:56 +0100 Subject: [PATCH 525/916] restored global map --- apps/openmw/mwrender/localmap.cpp | 47 +++++++++++-------------------- apps/openmw/mwrender/localmap.hpp | 11 +------- 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index ccad0a5e8..e0b7d9a11 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -191,6 +191,20 @@ void LocalMap::render(const float x, const float y, mCellCamera->setFarClipDistance(0); // infinite mCellCamera->setOrthoWindow(xw, yw); + mCellCamera->setPosition(Vector3(x, zhigh+100000, y)); + + // disable fog (only necessary for fixed function, the shader based + // materials already do this through local_map material configuration) + float oldFogStart = mRendering->getScene()->getFogStart(); + float oldFogEnd = mRendering->getScene()->getFogEnd(); + Ogre::ColourValue oldFogColour = mRendering->getScene()->getFogColour(); + mRendering->getScene()->setFog(FOG_NONE); + + // set up lighting + Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); + mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); + mRenderingManager->disableLights(true); + mLight->setVisible(true); TexturePtr tex; // try loading from memory @@ -216,8 +230,6 @@ void LocalMap::render(const float x, const float y, RenderTarget* rtt = tex->getBuffer()->getRenderTarget(); - mCameraSettings[rtt] = Vector3(x, zhigh+100000, y); - rtt->setAutoUpdated(false); Viewport* vp = rtt->addViewport(mCellCamera); vp->setOverlaysEnabled(false); @@ -228,8 +240,7 @@ void LocalMap::render(const float x, const float y, // use fallback techniques without shadows and without mrt vp->setMaterialScheme("local_map"); - rtt->setAutoUpdated(true); - rtt->addListener(this); + rtt->update(); // create "fog of war" texture TexturePtr tex2 = TextureManager::getSingleton().createManual( @@ -260,36 +271,12 @@ void LocalMap::render(const float x, const float y, //rtt->writeContentsToFile("./" + texture + ".jpg"); } } -} - -void LocalMap::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ - // disable fog (only necessary for fixed function, the shader based - // materials already do this through local_map material configuration) - mOldFogStart = mRendering->getScene()->getFogStart(); - mOldFogEnd = mRendering->getScene()->getFogEnd(); - mOldFogClr = mRendering->getScene()->getFogColour(); - mRendering->getScene()->setFog(FOG_NONE); - - mOldAmbient = mRendering->getScene()->getAmbientLight(); - mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); - - mCellCamera->setPosition(mCameraSettings[evt.source]); - - mRenderingManager->disableLights(true); - mLight->setVisible(true); - evt.source->setAutoUpdated(false); -} - -void LocalMap::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ mRenderingManager->enableLights(true); mLight->setVisible(false); - evt.source->removeListener(this); // re-enable fog - mRendering->getScene()->setFog(FOG_LINEAR, mOldFogClr, 0, mOldFogStart, mOldFogEnd); - mRendering->getScene()->setAmbientLight(mOldAmbient); + mRendering->getScene()->setFog(FOG_LINEAR, oldFogColour, 0, oldFogStart, oldFogEnd); + mRendering->getScene()->setAmbientLight(oldAmbient); } void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index afdf4b6e5..9c82258f9 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -5,7 +5,6 @@ #include #include -#include namespace MWWorld { @@ -19,7 +18,7 @@ namespace MWRender /// /// \brief Local map rendering /// - class LocalMap : public Ogre::RenderTargetListener + class LocalMap { public: LocalMap(OEngine::Render::OgreRenderer*, MWRender::RenderingManager* rendering); @@ -71,9 +70,6 @@ namespace MWRender */ bool isPositionExplored (float nX, float nY, int x, int y, bool interior); - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - private: OEngine::Render::OgreRenderer* mRendering; MWRender::RenderingManager* mRenderingManager; @@ -122,11 +118,6 @@ namespace MWRender Ogre::AxisAlignedBox mBounds; std::string mInteriorName; - Ogre::ColourValue mOldFogClr; - Ogre::ColourValue mOldAmbient; - float mOldFogStart; - float mOldFogEnd; - // maps texture name to according camera settings std::map mCameraSettings; }; From 3fe5757770b9abecd02cbb288f371c8208f92892 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Feb 2013 10:28:49 +0100 Subject: [PATCH 526/916] updated changelog for 0.21.0 again --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index 91690ff57..3124744c3 100644 --- a/readme.txt +++ b/readme.txt @@ -114,8 +114,10 @@ Bug #521: MWGui::InventoryWindow creates a duplicate player actor at the origin Bug #524: Beast races are able to wear shoes Bug #527: Background music fails to play Bug #533: The arch at Gnisis entrance is not displayed +Bug #534: Terrain gets its correct shape only some time after the cell is loaded Bug #536: The same entry can be added multiple times to the journal Bug #539: Race selection is broken +Bug #544: Terrain normal map corrupt when the map is rendered Feature #39: Video Playback Feature #151: ^-escape sequences in text output Feature #392: Add AI related script functions From cfceb450095db1ea1a8d91c21f86ecc81a85c6b1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Feb 2013 11:53:48 +0100 Subject: [PATCH 527/916] adjusted gcc settings again to avoid problems with older compiler versions --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 165db6b79..577b6f6b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,7 +306,7 @@ endif() # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++03 -pedantic -Wno-long-long) + add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long) # Silence warnings in OGRE headers. Remove once OGRE got fixed! add_definitions (-Wno-ignored-qualifiers) From c409f1184e9667d193eda048980329c9edbe1c71 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Feb 2013 12:19:06 +0100 Subject: [PATCH 528/916] cleaned up object movement and fixed a bug regarding local scripts --- apps/openmw/mwworld/worldimp.cpp | 64 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 24d139b37..609b6582d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -302,26 +302,26 @@ namespace MWWorld { return mGlobalVariables->getGlobals(); } - + std::string World::getCurrentCellName () const { std::string name; Ptr::CellStore *cell = mWorldScene->getCurrentCell(); if (cell->mCell->isExterior()) - { + { if (cell->mCell->mName != "") - { + { name = cell->mCell->mName; - } - else - { + } + else + { const ESM::Region* region = MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); if (region) name = region->mName; else - { + { const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().search("sDefaultCellname"); @@ -331,13 +331,13 @@ namespace MWWorld name = "Wilderness"; } - } - } - else - { + } + } + else + { name = cell->mCell->mName; - } - + } + return name; } @@ -426,12 +426,12 @@ namespace MWWorld if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); - + if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); } } - + void World::removeContainerScripts(const Ptr& reference) { if( reference.getTypeName()==typeid (ESM::Container).name() || @@ -456,7 +456,7 @@ namespace MWWorld if (reference.getRefData().isEnabled()) { reference.getRefData().disable(); - + if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); } @@ -687,14 +687,14 @@ namespace MWWorld void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { ESM::Position &pos = ptr.getRefData().getPosition(); - pos.pos[0] = x, pos.pos[1] = y, pos.pos[2] = z; + pos.pos[0] = x; + pos.pos[1] = y; + pos.pos[2] = z; Ogre::Vector3 vec(x, y, z); CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; - - removeContainerScripts(ptr); if (*currCell != newCell) { @@ -707,7 +707,8 @@ namespace MWWorld int cellY = newCell.mCell->getGridY(); mWorldScene->changeCell(cellX, cellY, pos, false); } - else { + else + { if (!mWorldScene->isCellActive(*currCell)) copyObjectToCell(ptr, newCell, pos); else if (!mWorldScene->isCellActive(newCell)) @@ -715,6 +716,7 @@ namespace MWWorld MWWorld::Class::get(ptr).copyToCell(ptr, newCell); mWorldScene->removeObjectFromScene(ptr); mLocalScripts.remove(ptr); + removeContainerScripts (ptr); haveToMove = false; } else @@ -722,10 +724,18 @@ namespace MWWorld MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); - addContainerScripts(copy, &newCell); - mRendering->moveObjectToCell(copy, vec, currCell); + std::string script = + MWWorld::Class::get(ptr).getScript(ptr); + if (!script.empty()) + { + mLocalScripts.remove(ptr); + removeContainerScripts (ptr); + mLocalScripts.add(script, copy); + addContainerScripts (copy, &newCell); + } + if (MWWorld::Class::get(ptr).isActor()) { MWBase::MechanicsManager *mechMgr = @@ -734,16 +744,6 @@ namespace MWWorld mechMgr->removeActor(ptr); mechMgr->addActor(copy); } - else - { - std::string script = - MWWorld::Class::get(ptr).getScript(ptr); - if (!script.empty()) - { - mLocalScripts.remove(ptr); - mLocalScripts.add(script, copy); - } - } } ptr.getRefData().setCount(0); } From 3772cd9257cf127fdbb476d169e831536852572a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 14:29:46 +0100 Subject: [PATCH 529/916] Refraction can be disabled separately now --- apps/openmw/mwgui/settingswindow.cpp | 6 ++++ apps/openmw/mwgui/settingswindow.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 22 +++++++++----- apps/openmw/mwrender/water.cpp | 10 ++++-- files/materials/core.h | 6 ---- files/materials/objects.shader | 11 ++----- files/materials/terrain.shader | 16 ++++------ files/materials/water.mat | 3 ++ files/materials/water.shader | 37 ++++++++++++++--------- files/mygui/openmw_settings_window.layout | 7 +++++ files/settings-default.cfg | 6 ++-- 11 files changed, 72 insertions(+), 53 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index c5c6eada2..343c96cec 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -123,6 +123,7 @@ namespace MWGui getWidget(mInvertYButton, "InvertYButton"); getWidget(mUISensitivitySlider, "UISensitivitySlider"); getWidget(mCameraSensitivitySlider, "CameraSensitivitySlider"); + getWidget(mRefractionButton, "RefractionButton"); mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -133,6 +134,7 @@ namespace MWGui mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mWaterShaderButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mRefractionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectObjectsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectTerrainButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectActorsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -248,6 +250,8 @@ namespace MWGui mShadersButton->setCaption (Settings::Manager::getBool("shaders", "Objects") ? "on" : "off"); mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); + mRefractionButton->setCaption (Settings::Manager::getBool("refraction", "Water") ? "on" : "off"); + if (!MWRender::RenderingManager::waterShaderSupported()) { mWaterShaderButton->setEnabled(false); @@ -376,6 +380,8 @@ namespace MWGui { if (_sender == mWaterShaderButton) Settings::Manager::setBool("shader", "Water", newState); + else if (_sender == mRefractionButton) + Settings::Manager::setBool("refraction", "Water", newState); else if (_sender == mUnderwaterButton) { Settings::Manager::setBool("underwater effect", "Water", newState); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 8ca3ad758..55cc0a870 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -51,6 +51,7 @@ namespace MWGui MyGUI::Button* mShadersButton; MyGUI::Button* mShaderModeButton; MyGUI::Button* mUnderwaterButton; + MyGUI::Button* mRefractionButton; MyGUI::Button* mShadowsEnabledButton; MyGUI::Button* mShadowsLargeDistance; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index aa73bc49b..69f3914e5 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -135,8 +135,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); - sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty(new sh::FloatValue( - 1.f))); + sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); applyCompositors(); @@ -757,6 +756,7 @@ Compositors* RenderingManager::getCompositors() void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) { bool changeRes = false; + bool rebuild = false; // rebuild static geometry (necessary after any material changes) for (Settings::CategorySettingVector::const_iterator it=settings.begin(); it != settings.end(); ++it) { @@ -794,18 +794,23 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec applyCompositors(); sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - mObjects.rebuildStaticGeometry (); + rebuild = true; mRendering.getViewport ()->setClearEveryFrame (true); } + else if (it->second == "refraction" && it->first == "Water") + { + sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); + rebuild = true; + } else if (it->second == "underwater effect" && it->first == "Water") { sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); - mObjects.rebuildStaticGeometry (); + rebuild = true; } else if (it->second == "shaders" && it->first == "Objects") { sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); - mObjects.rebuildStaticGeometry (); + rebuild = true; } else if (it->second == "shader mode" && it->first == "General") { @@ -818,13 +823,13 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec else lang = sh::Language_CG; sh::Factory::getInstance ().setCurrentLanguage (lang); - mObjects.rebuildStaticGeometry (); + rebuild = true; } else if (it->first == "Shadows") { mShadows->recreate (); - mObjects.rebuildStaticGeometry (); + rebuild = true; } } @@ -842,6 +847,9 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec if (mWater) mWater->processChangedSettings(settings); + + if (rebuild) + mObjects.rebuildStaticGeometry(); } void RenderingManager::setMenuTransparency(float val) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f2854c879..433aa8af8 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -430,8 +430,11 @@ void Water::applyRTT() delete mRefraction; mRefraction = NULL; - mRefraction = new Refraction(mCamera); - mRefraction->setHeight(mTop); + if (Settings::Manager::getBool("refraction", "Water")) + { + mRefraction = new Refraction(mCamera); + mRefraction->setHeight(mTop); + } } void Water::applyVisibilityMask() @@ -455,7 +458,8 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin it != settings.end(); ++it) { if ( it->first == "Water" && ( - it->second == "shader" + it->second == "shader" + || it->second == "refraction" || it->second == "rtt size")) applyRT = true; diff --git a/files/materials/core.h b/files/materials/core.h index e498a3809..3385e5fac 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -1,9 +1,3 @@ -//#define gammaCorrectRead(v) pow(max(v, 0.00001f), float3(gammaCorrection,gammaCorrection,gammaCorrection)) -//#define gammaCorrectOutput(v) pow(max(v, 0.00001f), float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) - -#define gammaCorrectRead(v) v -#define gammaCorrectOutput(v) v - #if SH_HLSL == 1 || SH_CG == 1 #define shTexture2D sampler2D diff --git a/files/materials/objects.shader b/files/materials/objects.shader index c68705c42..1e9c4a334 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -112,8 +112,6 @@ shUniform(float, far) @shAutoConstant(far, far_clip_distance) #endif - //shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) - #if LIGHTING shInput(float3, normalPassthrough) shInput(float3, objSpacePositionPassthrough) @@ -180,7 +178,6 @@ SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV); - shOutputColour(0).xyz = gammaCorrectRead(shOutputColour(0).xyz); #if LIGHTING float3 normal = normalize(normalPassthrough); @@ -271,7 +268,7 @@ // regular fog only if fragment is above water if (worldPos.y > waterLevel || waterEnabled != 1.f) #endif - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); #endif // prevent negative colour output (for example with negative lights) @@ -286,11 +283,11 @@ float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85)) *waterSunGradient * 0.5; + float3 waterSunColour = float3(0.0,1.0,0.85) *waterSunGradient * 0.5; float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = ( gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; + float3 watercolour = ( float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; @@ -303,8 +300,6 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); #endif - shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); - #if MRT shOutputColour(1) = float4(depthPassthrough / far,1,1,1); #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index dfe998210..9b891e1e8 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -137,8 +137,6 @@ shSampler2D(normalMap) // global normal map - //shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) - @shForeach(@shPropertyString(num_blendmaps)) shSampler2D(blendMap@shIterator) @@ -254,9 +252,9 @@ #if IS_FIRST_PASS == 1 && @shIterator == 0 // first layer of first pass doesn't need a blend map - albedo = gammaCorrectRead(shSample(diffuseMap0, UV * 10).rgb); + albedo = shSample(diffuseMap0, UV * 10).rgb; #else - albedo = shLerp(albedo, gammaCorrectRead(shSample(diffuseMap@shIterator, UV * 10).rgb), blendValues@shPropertyString(blendmap_component_@shIterator)); + albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); #endif @shEndForeach @@ -343,7 +341,7 @@ // regular fog only if fragment is above water if (worldPos.y > waterLevel) #endif - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); #endif // prevent negative colour output (for example with negative lights) @@ -358,12 +356,12 @@ float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85))*waterSunGradient * 0.5; + float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; - float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction + float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; + float3 waterext = float3(0.6, 0.9, 1.0);//water extinction watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; @@ -376,8 +374,6 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); #endif - shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); - #if MRT shOutputColour(1) = float4(depth / far,1,1,1); #endif diff --git a/files/materials/water.mat b/files/materials/water.mat index 2717f26fc..7546606fc 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -11,6 +11,9 @@ material Water fragment_program water_fragment cull_hardware none + + scene_blend alpha_blend + depth_write off texture_unit reflectionMap { diff --git a/files/materials/water.shader b/files/materials/water.shader index dbe36a91c..b02b4761c 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -62,6 +62,7 @@ // Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) #define RIPPLES 1 +#define REFRACTION @shGlobalSettingBool(refraction) #ifdef SH_VERTEX_SHADER @@ -123,9 +124,9 @@ #define REFR_BUMP 0.12 // refraction distortion amount #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering - #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering + #define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering - #define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction + #define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction #define SPEC_HARDNESS 256 // specular highlights hardness @@ -168,7 +169,9 @@ shUniform(float, far) @shAutoConstant(far, far_clip_distance) shSampler2D(reflectionMap) +#if REFRACTION shSampler2D(refractionMap) +#endif shSampler2D(depthMap) shSampler2D(normalMap) @@ -186,9 +189,6 @@ shUniform(float4, sunPosition) @shAutoConstant(sunPosition, light_position, 0) shUniform(float4, sunSpecular) @shAutoConstant(sunSpecular, light_specular_colour, 0) - - shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) - shUniform(float, renderTargetFlipping) @shAutoConstant(renderTargetFlipping, render_target_flipping) @@ -255,7 +255,7 @@ float s = shSaturate(dot(lR, vVec)*2.0-1.2); float lightScatter = shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); - float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*gammaCorrectRead(float3(1.0,0.4,0.0)), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); + float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*float3(1.0,0.4,0.0), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); // fresnel float ior = (cameraPos.y>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air @@ -264,32 +264,36 @@ fresnel = shSaturate(fresnel); // reflection - float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb); + float3 reflection = shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb; // refraction float3 R = reflect(vVec, normal); - float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(normal.xz*REFR_BUMP))*1.0).rgb); +#if REFRACTION + float3 refraction = shSample(refractionMap, (screenCoords-(normal.xz*REFR_BUMP))*1.0).rgb; // brighten up the refraction underwater refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction; - +#endif // specular float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); +#if REFRACTION shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; - +#else + shOutputColour(0).xyz = reflection + specular * sunSpecular.xyz; +#endif // fog if (isUnderwater == 1) { float waterSunGradient = dot(-vVec, -lVec); waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85))*waterSunGradient * 0.5; + float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; float waterGradient = dot(-vVec, float3(0.0,-1.0,0.0)); waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; - float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction + float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; + float3 waterext = float3(0.6, 0.9, 1.0);//water extinction watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); float darkness = VISIBILITY*2.0; @@ -302,11 +306,14 @@ else { float fogValue = shSaturate((length(cameraPos.xyz-position.xyz) - fogParams.y) * fogParams.w); - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColor), fogValue); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); } - shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); +#if REFRACTION shOutputColour(0).w = 1; +#else + shOutputColour(0).w = shSaturate(fresnel + specular); +#endif } #endif diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index f03305ae7..5b7f106f3 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -285,6 +285,13 @@ + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 31aa60c42..044cc3406 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -127,11 +127,10 @@ fog end factor = 1.0 num lights = 8 [Water] -# Enable this to get fancy-looking water with reflections and refractions -# Only available if object shaders are on -# All the settings below have no effect if this is false shader = false +refraction = false + rtt size = 512 reflect terrain = true reflect statics = false @@ -139,7 +138,6 @@ reflect small statics = false reflect actors = false reflect misc = false -# Enable underwater effect. It is not resource intensive, so only disable it if you have problems. underwater effect = false [Sound] From 1c604445ba4f25f4ed2cf92e105e2a57e291bfcf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 06:59:01 -0800 Subject: [PATCH 530/916] Store movement vectors as they get returned --- apps/openmw/mwmechanics/actors.cpp | 16 ++++++---------- apps/openmw/mwmechanics/actors.hpp | 7 ++++++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e829d4679..e01303c02 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -258,19 +258,15 @@ namespace MWMechanics if(!paused) { - PtrControllerMap::iterator player(mActors.end()); + mMovement.reserve(mActors.size()); + for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - if(iter->first.getRefData().getHandle() == "player") - { - /* Make sure player updates last (in case a cell transition occurs) */ - player = iter; - continue; - } - iter->second.update(duration); + Ogre::Vector3 movement = iter->second.update(duration); + mMovement.push_back(std::make_pair(iter->first, movement)); } - if(player != mActors.end()) - player->second.update(duration); + + mMovement.clear(); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 8c3df6c28..6968f3401 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -25,9 +25,14 @@ namespace MWMechanics { typedef std::map PtrControllerMap; PtrControllerMap mActors; - float mDuration; + + typedef std::vector > PtrMovementList; + PtrMovementList mMovement; + std::map mDeathCount; + float mDuration; + void updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused); void adjustMagicEffects (const MWWorld::Ptr& creature); From 499f3ac0d18165cdf0079fa5c711aa390993fd42 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 16:40:41 +0100 Subject: [PATCH 531/916] Slightly better ripple normal blending. Not physically accurate at all, but looks good. --- apps/openmw/mwrender/ripplesimulation.cpp | 10 +++++++--- apps/openmw/mwrender/ripplesimulation.hpp | 2 ++ apps/openmw/mwrender/water.cpp | 3 ++- files/materials/water.shader | 7 ++++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 043757e88..249397005 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -20,7 +20,8 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) mTextureSize(512), mRippleAreaLength(1000), mImpulseSize(20), - mTexelOffset(0,0) + mTexelOffset(0,0), + mFirstUpdate(true) { Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); @@ -106,7 +107,7 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) // try to keep 20 fps mTime += dt; - while (mTime >= 1/20.0) + while (mTime >= 1/20.0 || mFirstUpdate) { mPreviousFrameOffset = mCurrentFrameOffset; @@ -130,7 +131,10 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) heightMapToNormalMap(); swapHeightMaps(); - mTime -= 1/20.0; + if (!mFirstUpdate) + mTime -= 1/20.0; + else + mFirstUpdate = false; } sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 72ff3dbd8..c792a3214 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -34,6 +34,8 @@ private: float mRippleAreaLength; float mImpulseSize; + bool mFirstUpdate; + Ogre::Camera* mCamera; // own scenemanager to render our simulation diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 433aa8af8..4ff8945ac 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -401,7 +401,8 @@ void Water::update(float dt, Ogre::Vector3 player) mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - if (player.y <= mTop) + /// \todo player.y is the scene node position (which is above the head) and not the feet position + //if (player.y <= mTop) { mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } diff --git a/files/materials/water.shader b/files/materials/water.shader index b02b4761c..400fbefb2 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -120,8 +120,8 @@ #define WAVE_SCALE 75 // overall wave scale #define BUMP 1.5 // overall water surface bumpiness - #define REFL_BUMP 0.16 // reflection distortion amount - #define REFR_BUMP 0.12 // refraction distortion amount + #define REFL_BUMP 0.08 // reflection distortion amount + #define REFR_BUMP 0.06 // refraction distortion amount #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering #define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering @@ -232,7 +232,8 @@ float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2 - 1); normal_ripple = normal_ripple.xzy; - normal = normalize(normal + normal_ripple); + //normal = normalize(normal + normal_ripple); + normal = normalize(float3(normal.x + normal_ripple.x, normal.y, normal.z + normal_ripple.z)); // normal for sunlight scattering From 82e4da4e6455249ca402bf886382bd0263e17c8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 07:41:57 -0800 Subject: [PATCH 532/916] Get the half-extents from the physicactor --- apps/openmw/mwmechanics/character.cpp | 3 +-- apps/openmw/mwmechanics/movementsolver.cpp | 3 ++- apps/openmw/mwmechanics/movementsolver.hpp | 2 +- libs/openengine/bullet/physic.cpp | 14 ++++++++++++++ libs/openengine/bullet/physic.hpp | 5 +++++ 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b98a863ae..27c1dc851 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -191,8 +191,7 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * movement; - // FIXME: Get the actual radius for the object. Maybe this should go into mwworld to replace pmove? - Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration, Ogre::Vector3(15,15,30)); + Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration); MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); } diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 4a7a59cb3..f17671a61 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -76,7 +76,7 @@ float MovementSolver::getSlope(const Ogre::Vector3 &normal) } -Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents) +Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) { Ogre::Vector3 position(ptr.getRefData().getPosition().pos); @@ -96,6 +96,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = mPhysicActor->getHalfExtents(); Ogre::Vector3 lastNormal(0.0f); Ogre::Vector3 currentNormal(0.0f); diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 450bc055e..a8b9bf144 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -25,7 +25,7 @@ namespace MWMechanics MovementSolver(); virtual ~MovementSolver(); - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, const Ogre::Vector3 &halfExtents); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); private: bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b39ba53a2..7f0f6e2f9 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -156,6 +156,20 @@ namespace Physic } } + Ogre::Vector3 PhysicActor::getHalfExtents() const + { + if(mBody) + { + btBoxShape *box = static_cast(mBody->getCollisionShape()); + if(box != NULL) + { + btVector3 size = box->getHalfExtentsWithMargin(); + return Ogre::Vector3(size.getX(), size.getY(), size.getZ()); + } + } + return Ogre::Vector3(0.0f); + } + void PhysicActor::runPmove(){ Pmove(pmove); Ogre::Vector3 newpos = pmove->ps.origin; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 76bdb491d..d98625c0a 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -117,6 +117,11 @@ namespace Physic */ void setScale(float scale); + /** + * Returns the half extents for this PhysiActor + */ + Ogre::Vector3 getHalfExtents() const; + /** * Runs pmove for this PhysicActor */ From a782a9109b131c04da01a0052afcbf8d7c208d97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:24:22 -0800 Subject: [PATCH 533/916] Store the vertical velocity in the physic actor --- apps/openmw/mwmechanics/movementsolver.cpp | 3 ++- apps/openmw/mwmechanics/movementsolver.hpp | 2 -- libs/openengine/bullet/physic.cpp | 13 ++++++++++++- libs/openengine/bullet/physic.hpp | 11 +++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index f17671a61..3fddb28fe 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -15,7 +15,6 @@ namespace MWMechanics MovementSolver::MovementSolver() : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) - , verticalVelocity(0.0f) { } @@ -89,6 +88,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. float maxslope=45; + float verticalVelocity = mPhysicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); @@ -156,6 +156,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 verticalVelocity = clippedVelocity.z; verticalVelocity -= time*400; + mPhysicActor->setVerticalForce(verticalVelocity); return newPosition; } diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index a8b9bf144..6a965b56a 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -37,8 +37,6 @@ namespace MWMechanics OEngine::Physic::PhysicEngine *mEngine; OEngine::Physic::PhysicActor *mPhysicActor; - - float verticalVelocity; }; } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7f0f6e2f9..1ae916f81 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -28,7 +28,7 @@ namespace Physic }; PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0) + mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -170,6 +170,17 @@ namespace Physic return Ogre::Vector3(0.0f); } + void PhysicActor::setVerticalForce(float force) + { + verticalForce = force; + } + + float PhysicActor::getVerticalForce() const + { + return verticalForce; + } + + void PhysicActor::runPmove(){ Pmove(pmove); Ogre::Vector3 newpos = pmove->ps.origin; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index d98625c0a..daf1c09f2 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -122,6 +122,16 @@ namespace Physic */ Ogre::Vector3 getHalfExtents() const; + /** + * Sets the current amount of vertical force (gravity) affecting this physic actor + */ + void setVerticalForce(float force); + + /** + * Gets the current amount of vertical force (gravity) affecting this physic actor + */ + float getVerticalForce() const; + /** * Runs pmove for this PhysicActor */ @@ -141,6 +151,7 @@ namespace Physic Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; + float verticalForce; bool collisionMode; std::string mMesh; PhysicEngine* mEngine; From d50832081cddc2f1238d41de85c62657ace1f3f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:37:02 -0800 Subject: [PATCH 534/916] Remove the unneeded PhysicActor field from MovementSolver --- apps/openmw/mwmechanics/movementsolver.cpp | 24 +++++++++++----------- apps/openmw/mwmechanics/movementsolver.hpp | 2 -- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp index 3fddb28fe..544cb2ab8 100644 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ b/apps/openmw/mwmechanics/movementsolver.cpp @@ -13,6 +13,8 @@ namespace MWMechanics { +static const float sMaxSlope = 45.0f; + MovementSolver::MovementSolver() : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) { @@ -49,17 +51,16 @@ void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) { - static const float maxslope = 45.0f; traceResults trace; // no initialization needed newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > maxslope)) + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); - if(getSlope(trace.planenormal) < maxslope) + if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. position = trace.endpos; @@ -80,23 +81,22 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 Ogre::Vector3 position(ptr.getRefData().getPosition().pos); /* Anything to collide with? */ - mPhysicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); - if(!mPhysicActor || !mPhysicActor->getCollisionMode()) + OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); + if(!physicActor || !physicActor->getCollisionMode()) return position + movement; traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - float maxslope=45; - float verticalVelocity = mPhysicActor->getVerticalForce(); + float verticalVelocity = physicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = mPhysicActor->getRotation().getYaw().valueDegrees(); - Ogre::Vector3 halfExtents = mPhysicActor->getHalfExtents(); + float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); Ogre::Vector3 lastNormal(0.0f); Ogre::Vector3 currentNormal(0.0f); @@ -106,7 +106,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); if(trace.fraction < 1.0f) { - if(getSlope(trace.planenormal) > maxslope) + if(getSlope(trace.planenormal) > sMaxSlope) { // if we're on a really steep slope, don't listen to user input clippedVelocity.x = clippedVelocity.y = 0.0f; @@ -129,7 +129,7 @@ Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 if(trace.fraction != 1.0f) { //std::cout<<"angle: "< maxslope || currentNormal == lastNormal) + if(getSlope(currentNormal) > sMaxSlope || currentNormal == lastNormal) { if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) std::cout<< "stepped" <setVerticalForce(verticalVelocity); + physicActor->setVerticalForce(verticalVelocity); return newPosition; } diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp index 6a965b56a..1c56df036 100644 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ b/apps/openmw/mwmechanics/movementsolver.hpp @@ -13,7 +13,6 @@ namespace OEngine namespace Physic { class PhysicEngine; - class PhysicActor; } } @@ -36,7 +35,6 @@ namespace MWMechanics float getSlope(const Ogre::Vector3 &normal); OEngine::Physic::PhysicEngine *mEngine; - OEngine::Physic::PhysicActor *mPhysicActor; }; } From 3251796ba04b513881658f693b14b7762d11ae77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 09:57:08 -0800 Subject: [PATCH 535/916] Fix left/right movement --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8b..991cf4f51 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -271,12 +271,12 @@ namespace MWInput if (actionIsActive(A_MoveLeft)) { mPlayer.setAutoMove (false); - mPlayer.setLeftRight (1); + mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { mPlayer.setAutoMove (false); - mPlayer.setLeftRight (-1); + mPlayer.setLeftRight (1); } else mPlayer.setLeftRight (0); From c4d518132f83cb0697361fa98e69e3b1bd6a8b88 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 19:22:08 +0100 Subject: [PATCH 536/916] With the 1x1 background window trick, we can apply VSync without restart. Some issues left though. --- apps/openmw/mwbase/inputmanager.hpp | 3 +++ apps/openmw/mwgui/settingswindow.cpp | 8 ++----- apps/openmw/mwinput/inputmanagerimp.cpp | 28 ++++++++++++++++++---- apps/openmw/mwinput/inputmanagerimp.hpp | 8 +++++++ apps/openmw/mwrender/renderingmanager.cpp | 29 ++++++++++++++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 2 ++ libs/openengine/ogre/renderer.cpp | 25 +++++++++++++++---- libs/openengine/ogre/renderer.hpp | 3 +++ 8 files changed, 90 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 8293cbfa7..f69e1a152 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -39,6 +39,9 @@ namespace MWBase virtual int getNumActions() = 0; virtual void enableDetectingBindingMode (int action) = 0; virtual void resetToDefaultBindings() = 0; + + virtual void create () = 0; + virtual void destroy () = 0; }; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 343c96cec..75fc2b7a2 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -370,14 +370,10 @@ namespace MWGui apply(); } } - else if (_sender == mVSyncButton) - { - Settings::Manager::setBool("vsync", "Video", newState); - MWBase::Environment::get().getWindowManager()-> - messageBox("VSync will be applied after a restart", std::vector()); - } else { + if (_sender == mVSyncButton) + Settings::Manager::setBool("vsync", "Video", newState); if (_sender == mWaterShaderButton) Settings::Manager::setBool("shader", "Water", newState); else if (_sender == mRefractionButton) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8b..95d221933 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -41,9 +41,11 @@ namespace MWInput , mMouseX(ogre.getWindow()->getWidth ()/2.f) , mMouseY(ogre.getWindow()->getHeight ()/2.f) , mMouseWheel(0) - , mUserFile(userFile) , mDragDrop(false) , mGuiCursorEnabled(false) + , mDebug(debug) + , mUserFile(userFile) + , mUserFileExists(userFileExists) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) @@ -51,8 +53,15 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) + , mCreated(false) { - Ogre::RenderWindow* window = ogre.getWindow (); + create(); + } + + + void InputManager::create() + { + Ogre::RenderWindow* window = mOgre.getWindow (); size_t windowHnd; resetIdleTime(); @@ -67,7 +76,7 @@ namespace MWInput // Set non-exclusive mouse and keyboard input if the user requested // it. - if (debug) + if (mDebug) { #if defined OIS_WIN32_PLATFORM pl.insert(std::make_pair(std::string("w32_mouse"), @@ -112,7 +121,7 @@ namespace MWInput MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mMouse->getMouseState ().Z.abs); - std::string file = userFileExists ? userFile : ""; + std::string file = mUserFileExists ? mUserFile : ""; mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); loadKeyDefaults(); @@ -131,9 +140,11 @@ namespace MWInput mControlSwitch["vanitymode"] = true; changeInputMode(false); + + mCreated = true; } - InputManager::~InputManager() + void InputManager::destroy() { mInputCtrl->save (mUserFile); @@ -142,6 +153,12 @@ namespace MWInput mInputManager->destroyInputObject(mKeyboard); mInputManager->destroyInputObject(mMouse); OIS::InputManager::destroyInputSystem(mInputManager); + mCreated = false; + } + + InputManager::~InputManager() + { + destroy(); } void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) @@ -239,6 +256,7 @@ namespace MWInput void InputManager::update(float dt, bool loading) { + if (!mCreated) return; // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f28..100bba4fb 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -131,6 +131,8 @@ namespace MWInput std::string mUserFile; + bool mCreated; + bool mDragDrop; bool mInvertY; @@ -148,9 +150,15 @@ namespace MWInput float mMouseX; float mMouseY; int mMouseWheel; + bool mDebug; + bool mUserFileExists; std::map mControlSwitch; + public: + virtual void create(); + virtual void destroy(); + private: void adjustMouseRegion(int width, int height); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 69f3914e5..9e50b2bce 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -46,7 +46,8 @@ namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) - : mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0), mPhysicsEngine(engine) + : mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0), mPhysicsEngine(engine), + mRecreateWindowInNextFrame(false) { // select best shader mode bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); @@ -323,6 +324,22 @@ RenderingManager::moveObjectToCell( void RenderingManager::update (float duration, bool paused) { + if (mRecreateWindowInNextFrame) + { + MWBase::Environment::get().getInputManager()->destroy(); + + OEngine::Render::WindowSettings windowSettings; + windowSettings.fullscreen = Settings::Manager::getBool("fullscreen", "Video"); + windowSettings.window_x = Settings::Manager::getInt("resolution x", "Video"); + windowSettings.window_y = Settings::Manager::getInt("resolution y", "Video"); + windowSettings.vsync = Settings::Manager::getBool("vsync", "Video"); + std::string aa = Settings::Manager::getString("antialiasing", "Video"); + windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + mRendering.recreateWindow("OpenMW", windowSettings); + + MWBase::Environment::get().getInputManager()->create(); + mRecreateWindowInNextFrame = false; + } Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -756,6 +773,7 @@ Compositors* RenderingManager::getCompositors() void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) { bool changeRes = false; + bool recreateWindow = false; bool rebuild = false; // rebuild static geometry (necessary after any material changes) for (Settings::CategorySettingVector::const_iterator it=settings.begin(); it != settings.end(); ++it) @@ -774,6 +792,8 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec || it->second == "resolution y" || it->second == "fullscreen")) changeRes = true; + else if (it->first == "Video" && it->second == "vsync") + recreateWindow = true; else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); else if ((it->second == "texture filtering" && it->first == "General") @@ -845,6 +865,13 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } + if (recreateWindow) + { + mRecreateWindowInNextFrame = true; + // We can not do this now, because this might get triggered from the input listener + // and destroying/recreating the input system at that point would cause a crash + } + if (mWater) mWater->processChangedSettings(settings); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 71ac742c2..670f3dc85 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -260,6 +260,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList MWRender::Compositors* mCompositors; VideoPlayer* mVideoPlayer; + + bool mRecreateWindowInNextFrame; }; } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 039aba226..e0abf420e 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -205,13 +205,31 @@ void OgreRenderer::configure(const std::string &logPath, rs->setConfigOption ("RTT Preferred Mode", rttMode); } +void OgreRenderer::recreateWindow(const std::string &title, const WindowSettings &settings) +{ + Ogre::ColourValue viewportBG = mView->getBackgroundColour(); + + mRoot->destroyRenderTarget(mWindow); + NameValuePairList params; + params.insert(std::make_pair("title", title)); + params.insert(std::make_pair("FSAA", settings.fsaa)); + params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); + + mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); + + // Create one viewport, entire window + mView = mWindow->addViewport(mCamera); + mView->setBackgroundColour(viewportBG); + + adjustViewport(); +} + void OgreRenderer::createWindow(const std::string &title, const WindowSettings& settings) { assert(mRoot); mRoot->initialise(false); // create a hidden 1x1 background window to keep resources when recreating the secondary (real) window - /* NameValuePairList params_; params_.insert(std::make_pair("title", title)); params_.insert(std::make_pair("FSAA", "0")); @@ -219,7 +237,6 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& params_.insert(std::make_pair("hidden", "true")); Ogre::RenderWindow* hiddenWindow = mRoot->createRenderWindow("InactiveHidden", 1, 1, false, ¶ms_); hiddenWindow->setActive(false); - */ NameValuePairList params; params.insert(std::make_pair("title", title)); @@ -271,12 +288,12 @@ void OgreRenderer::adjustViewport() void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) { - Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); + //Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); } void OgreRenderer::removeWindowEventListener(Ogre::WindowEventListener* listener) { - Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); + //Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); } void OgreRenderer::setFov(float fov) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index a8788dfca..251dc9c54 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -66,6 +66,7 @@ namespace OEngine #endif class Fader; + class OgreRenderer { #if defined(__APPLE__) && !defined(__LP64__) @@ -138,6 +139,8 @@ namespace OEngine /// Create a window with the given title void createWindow(const std::string &title, const WindowSettings& settings); + void recreateWindow (const std::string &title, const WindowSettings& settings); + /// Set up the scene manager, camera and viewport void createScene(const std::string& camName="Camera",// Camera name float fov=55, // Field of view angle From 2cdda967980acf429ab05d64358c8100e5813795 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 10:23:26 -0800 Subject: [PATCH 537/916] Clear out some unneeded doPhysics stuff --- apps/openmw/mwworld/physicssystem.cpp | 58 --------------------------- apps/openmw/mwworld/physicssystem.hpp | 3 -- apps/openmw/mwworld/worldimp.cpp | 43 -------------------- 3 files changed, 104 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9e2e94143..7d77718a3 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -190,66 +190,8 @@ namespace MWWorld //set the DebugRenderingMode. To disable it,set it to 0 //eng->setDebugRenderingMode(1); - //set the movement keys to 0 (no movement) for every actor) - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - OEngine::Physic::PhysicActor* act = it->second; - act->setMovement(0,0,0); - } - - playerMove::playercmd& pm_ref = playerphysics->cmd; - - - pm_ref.rightmove = 0; - pm_ref.forwardmove = 0; - pm_ref.upmove = 0; - - - //playerphysics->ps.move_type = PM_NOCLIP; - for (std::vector >::const_iterator iter (actors.begin()); - iter!=actors.end(); ++iter) - { - //dirty stuff to get the camera orientation. Must be changed! - if (iter->first == "player") { - playerphysics->ps.viewangles.x = - Ogre::Radian(mPlayerData.pitch).valueDegrees(); - - - - playerphysics->ps.viewangles.y = - Ogre::Radian(mPlayerData.yaw).valueDegrees() + 90; - - pm_ref.rightmove = iter->second.x; - pm_ref.forwardmove = -iter->second.y; - pm_ref.upmove = iter->second.z; - } - } - mEngine->stepSimulation(dt); } - std::vector< std::pair > PhysicsSystem::doPhysicsFixed ( - const std::vector >& actors) - { - Pmove(playerphysics); - - - std::vector< std::pair > response; - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { - - Ogre::Vector3 coord = it->second->getPosition(); - if(it->first == "player"){ - - coord = playerphysics->ps.origin ; - - } - - - response.push_back(std::pair(it->first, coord)); - } - - return response; - } void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 81715c31e..b28f651f6 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -17,9 +17,6 @@ namespace MWWorld void doPhysics(float duration, const std::vector >& actors); ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - std::vector< std::pair > doPhysicsFixed (const std::vector >& actors); - ///< do physics with fixed timestep - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - void addObject (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 246467fb0..5f6a2f4a7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -838,49 +838,6 @@ namespace MWWorld float duration) { mPhysics->doPhysics(duration, actors); - - const int tick = 16; // 16 ms ^= 60 Hz - - // Game clock part of the loop, contains everything that has to be executed in a fixed timestep - long long dt = mTimer.getMilliseconds() - lastTick; - if (dt >= 100) - { - // throw away wall clock time if necessary to keep the framerate above the minimum of 10 fps - lastTick += (dt - 100); - dt = 100; - } - while (dt >= tick) - { - dt -= tick; - lastTick += tick; - - std::vector< std::pair > vectors = mPhysics->doPhysicsFixed (actors); - - std::vector< std::pair >::iterator player = vectors.end(); - - for (std::vector< std::pair >::iterator it = vectors.begin(); - it!= vectors.end(); ++it) - { - if (it->first=="player") - { - player = it; - } - else - { - MWWorld::Ptr ptr = getPtrViaHandle (it->first); - moveObjectImp (ptr, it->second.x, it->second.y, it->second.z); - } - } - - // Make sure player is moved last (otherwise the cell might change in the middle of an update - // loop) - if (player!=vectors.end()) - { - if (moveObjectImp (getPtrViaHandle (player->first), - player->second.x, player->second.y, player->second.z) == true) - return; // abort the current loop if the cell has changed - } - } } bool World::toggleCollisionMode() From 0a4568bd11cf6d6a7e9f4f7cbd3e96d7d691faae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 11:03:39 -0800 Subject: [PATCH 538/916] Move the PtrMovementList typedef to MWWorld Use it for the doPhysics parameter, too --- apps/openmw/mwbase/world.hpp | 5 +++-- apps/openmw/mwmechanics/actors.hpp | 4 ++-- apps/openmw/mwworld/physicssystem.cpp | 7 ------- apps/openmw/mwworld/physicssystem.hpp | 3 --- apps/openmw/mwworld/worldimp.cpp | 4 +--- apps/openmw/mwworld/worldimp.hpp | 3 +-- 6 files changed, 7 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 5f6e27867..b5d8aec9c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -52,6 +52,8 @@ namespace MWWorld class TimeStamp; class ESMStore; class RefData; + + typedef std::vector > PtrMovementList; } namespace MWBase @@ -233,8 +235,7 @@ namespace MWBase virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0; ///< Convert position to cell numbers - virtual void doPhysics (const std::vector >& actors, - float duration) = 0; + virtual void doPhysics (const MWWorld::PtrMovementList &actors, float duration) = 0; ///< Run physics simulation and modify \a world accordingly. virtual bool toggleCollisionMode() = 0; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 6968f3401..fbd787e83 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -7,6 +7,7 @@ #include #include "character.hpp" +#include "../mwbase/world.hpp" namespace Ogre { @@ -26,8 +27,7 @@ namespace MWMechanics typedef std::map PtrControllerMap; PtrControllerMap mActors; - typedef std::vector > PtrMovementList; - PtrMovementList mMovement; + MWWorld::PtrMovementList mMovement; std::map mDeathCount; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7d77718a3..c95abc5a0 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -185,13 +185,6 @@ namespace MWWorld } } - void PhysicsSystem::doPhysics(float dt, const std::vector >& actors) - { - //set the DebugRenderingMode. To disable it,set it to 0 - //eng->setDebugRenderingMode(1); - - } - void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index b28f651f6..06b29d290 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -14,9 +14,6 @@ namespace MWWorld PhysicsSystem (OEngine::Render::OgreRenderer &_rend); ~PhysicsSystem (); - void doPhysics(float duration, const std::vector >& actors); - ///< do physics with dt - Usage: first call doPhysics with frame dt, then call doPhysicsFixed as often as time steps have passed - void addObject (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5f6a2f4a7..d900f555c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -834,10 +834,8 @@ namespace MWWorld --cellY; } - void World::doPhysics (const std::vector >& actors, - float duration) + void World::doPhysics(const PtrMovementList &actors, float duration) { - mPhysics->doPhysics(duration, actors); } bool World::toggleCollisionMode() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 062387e92..597766469 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -263,8 +263,7 @@ namespace MWWorld virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; ///< Convert position to cell numbers - virtual void doPhysics (const std::vector >& actors, - float duration); + virtual void doPhysics(const PtrMovementList &actors, float duration); ///< Run physics simulation and modify \a world accordingly. virtual bool toggleCollisionMode(); From 31f760cccec9a1bab571181e38699f8357b8b285 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 20:26:13 +0100 Subject: [PATCH 539/916] Fixing issues from last commit: restored input and occlusion queries --- apps/openmw/mwinput/inputmanagerimp.cpp | 11 +++-------- apps/openmw/mwinput/inputmanagerimp.hpp | 2 -- apps/openmw/mwrender/occlusionquery.cpp | 13 ++++++++++++- apps/openmw/mwrender/occlusionquery.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 13 ++++++++++++- apps/openmw/mwrender/water.cpp | 2 +- libs/openengine/ogre/renderer.cpp | 4 ++-- 7 files changed, 30 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 95d221933..00849503c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -53,9 +53,10 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) - , mCreated(false) { create(); + + changeInputMode(false); } @@ -138,10 +139,6 @@ namespace MWInput mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; - - changeInputMode(false); - - mCreated = true; } void InputManager::destroy() @@ -153,7 +150,6 @@ namespace MWInput mInputManager->destroyInputObject(mKeyboard); mInputManager->destroyInputObject(mMouse); OIS::InputManager::destroyInputSystem(mInputManager); - mCreated = false; } InputManager::~InputManager() @@ -250,13 +246,12 @@ namespace MWInput case A_ToggleHUD: mWindows.toggleHud(); break; - } + } } } void InputManager::update(float dt, bool loading) { - if (!mCreated) return; // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 100bba4fb..7be35ee0b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -131,8 +131,6 @@ namespace MWInput std::string mUserFile; - bool mCreated; - bool mDragDrop; bool mInvertY; diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index c9e649fe6..8d16d7b7d 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -15,7 +15,7 @@ using namespace Ogre; OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNode* sunNode) : mSunTotalAreaQuery(0), mSunVisibleAreaQuery(0), mSingleObjectQuery(0), mActiveQuery(0), mDoQuery(0), mSunVisibility(0), mQuerySingleObjectStarted(false), mTestResult(false), - mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mDoQuery2(false), + mQuerySingleObjectRequested(false), mWasVisible(false), mObjectWasVisible(false), mBBNode(0), mActive(false) { mRendering = renderer; @@ -94,6 +94,9 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod OcclusionQuery::~OcclusionQuery() { + mRendering->getScene()->removeRenderObjectListener (this); + mRendering->getScene()->removeRenderQueueListener(this); + RenderSystem* renderSystem = Root::getSingleton().getRenderSystem(); if (mSunTotalAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunTotalAreaQuery); if (mSunVisibleAreaQuery) renderSystem->destroyHardwareOcclusionQuery(mSunVisibleAreaQuery); @@ -109,6 +112,7 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass const LightList* pLightList, bool suppressRenderStateChanges) { if (!mActive) return; + // The following code activates and deactivates the occlusion queries // so that the queries only include the rendering of the intended meshes @@ -116,6 +120,7 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass // Each occlusion query should only last a single rendering if (mActiveQuery != NULL) { + std::cout << "ending query (notifyRenderSingleObject)" << std::endl; mActiveQuery->endOcclusionQuery(); mActiveQuery = NULL; } @@ -123,6 +128,7 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass // Open a new occlusion query if (mDoQuery == true) { + std::cout << "opening new query" << std::endl; if (rend == mBBQueryTotal) { mActiveQuery = mSunTotalAreaQuery; @@ -208,6 +214,7 @@ void OcclusionQuery::update(float duration) && !mSunVisibleAreaQuery->isStillOutstanding() && !mSingleObjectQuery->isStillOutstanding()) { + std::cout << "update(), nothing is outstanding"<< std::endl; unsigned int totalPixels; unsigned int visiblePixels; @@ -243,6 +250,8 @@ void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNod assert( !occlusionTestPending() && "Occlusion test still pending"); + std::cout << "Occlusion test called " << std::endl; + mBBQuerySingleObject->setVisible(true); mObjectNode->setPosition(position); @@ -250,6 +259,8 @@ void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNod mObjectNode->setScale( Vector3(1,1,1)*(position - mRendering->getCamera()->getRealPosition()).length() ); mQuerySingleObjectRequested = true; + + mDoQuery = true; } bool OcclusionQuery::occlusionTestPending() diff --git a/apps/openmw/mwrender/occlusionquery.hpp b/apps/openmw/mwrender/occlusionquery.hpp index af6f668c1..c7a5757d3 100644 --- a/apps/openmw/mwrender/occlusionquery.hpp +++ b/apps/openmw/mwrender/occlusionquery.hpp @@ -95,7 +95,6 @@ namespace MWRender bool mSupported; bool mDoQuery; - bool mDoQuery2; bool mQuerySingleObjectRequested; bool mQuerySingleObjectStarted; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9e50b2bce..afbdbb06f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -326,6 +326,10 @@ void RenderingManager::update (float duration, bool paused) { if (mRecreateWindowInNextFrame) { + mRecreateWindowInNextFrame = false; + + mRendering.removeWindowEventListener(this); + mRendering.getWindow()->removeListener(this); MWBase::Environment::get().getInputManager()->destroy(); OEngine::Render::WindowSettings windowSettings; @@ -338,8 +342,15 @@ void RenderingManager::update (float duration, bool paused) mRendering.recreateWindow("OpenMW", windowSettings); MWBase::Environment::get().getInputManager()->create(); - mRecreateWindowInNextFrame = false; + mRendering.setWindowEventListener (this); + mRendering.getWindow()->addListener(this); + + // this is necessary, otherwise it would just endlessly wait for the last query and it would never return + delete mOcclusionQuery; + mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); } + + Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 4ff8945ac..867829564 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -418,7 +418,7 @@ void Water::applyRTT() mReflection = NULL; // Create rendertarget for reflection - int rttsize = Settings::Manager::getInt("rtt size", "Water"); + //int rttsize = Settings::Manager::getInt("rtt size", "Water"); if (Settings::Manager::getBool("shader", "Water")) { diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index e0abf420e..c4f35e087 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -288,12 +288,12 @@ void OgreRenderer::adjustViewport() void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) { - //Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, listener); } void OgreRenderer::removeWindowEventListener(Ogre::WindowEventListener* listener) { - //Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, listener); } void OgreRenderer::setFov(float fov) From 608c112f34461760264240ded5f5140d2a24c7c2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 20:48:25 +0100 Subject: [PATCH 540/916] Supply the new render window to mygui --- apps/openmw/mwgui/loadingscreen.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++++++++++++--- apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwrender/occlusionquery.cpp | 5 ----- libs/openengine/gui/manager.cpp | 6 ++++++ libs/openengine/gui/manager.hpp | 2 ++ 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index c14087a3b..24b385071 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -19,6 +19,8 @@ namespace MWGui void onResChange(int w, int h); + void updateWindow(Ogre::RenderWindow* rw) { mWindow = rw; } + private: bool mFirstLoad; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a1f915ac9..3ae0f37c5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -56,10 +56,11 @@ using namespace MWGui; WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, + const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage) : mGuiManager(NULL) + , mRendering(ogre) , mHud(NULL) , mMap(NULL) , mMenu(NULL) @@ -111,7 +112,7 @@ WindowManager::WindowManager( { // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); + mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); mGui = mGuiManager->getGui(); //Register own widgets with MyGUI @@ -172,7 +173,7 @@ WindowManager::WindowManager( mEnchantingDialog = new EnchantingDialog(*this); mTrainingWindow = new TrainingWindow(*this); - mLoadingScreen = new LoadingScreen(mOgre->getScene (), mOgre->getWindow (), *this); + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); @@ -763,6 +764,7 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); bool changeRes = false; + bool windowRecreated = false; for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { @@ -772,6 +774,8 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector { changeRes = true; } + else if (it->first == "Video" && it->second == "vsync") + windowRecreated = true; else if (it->first == "HUD" && it->second == "crosshair") mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); else if (it->first == "GUI" && it->second == "subtitles") @@ -795,6 +799,11 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); mInputBlocker->setSize(MyGUI::IntSize(x,y)); } + if (windowRecreated) + { + mGuiManager->updateWindow (mRendering->getWindow ()); + mLoadingScreen->updateWindow (mRendering->getWindow ()); + } } void WindowManager::pushGuiMode(GuiMode mode) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8bcb88e22..bae195669 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -229,6 +229,7 @@ namespace MWGui private: OEngine::GUI::MyGUIManager *mGuiManager; + OEngine::Render::OgreRenderer *mRendering; HUD *mHud; MapWindow *mMap; MainMenu *mMenu; diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 8d16d7b7d..81a3f4327 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -120,7 +120,6 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass // Each occlusion query should only last a single rendering if (mActiveQuery != NULL) { - std::cout << "ending query (notifyRenderSingleObject)" << std::endl; mActiveQuery->endOcclusionQuery(); mActiveQuery = NULL; } @@ -128,7 +127,6 @@ void OcclusionQuery::notifyRenderSingleObject(Renderable* rend, const Pass* pass // Open a new occlusion query if (mDoQuery == true) { - std::cout << "opening new query" << std::endl; if (rend == mBBQueryTotal) { mActiveQuery = mSunTotalAreaQuery; @@ -214,7 +212,6 @@ void OcclusionQuery::update(float duration) && !mSunVisibleAreaQuery->isStillOutstanding() && !mSingleObjectQuery->isStillOutstanding()) { - std::cout << "update(), nothing is outstanding"<< std::endl; unsigned int totalPixels; unsigned int visiblePixels; @@ -250,8 +247,6 @@ void OcclusionQuery::occlusionTest(const Ogre::Vector3& position, Ogre::SceneNod assert( !occlusionTestPending() && "Occlusion test still pending"); - std::cout << "Occlusion test called " << std::endl; - mBBQuerySingleObject->setVisible(true); mObjectNode->setPosition(position); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 925891e1b..9cc2bf381 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -56,6 +56,12 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool mGui->initialise("core.xml"); } +void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) +{ + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); +} + void MyGUIManager::shutdown() { mGui->shutdown (); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index c0f98da88..39948a829 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -38,6 +38,8 @@ namespace GUI shutdown(); } + void updateWindow (Ogre::RenderWindow* wnd); + void setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")); void shutdown(); From 2c39760bd50284a809ba9fc091d01929e23eb3f1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 12:45:10 -0800 Subject: [PATCH 541/916] Move the movement solver code to mwworld's physics system --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/character.cpp | 26 +--- apps/openmw/mwmechanics/character.hpp | 4 - apps/openmw/mwmechanics/movementsolver.cpp | 164 --------------------- apps/openmw/mwmechanics/movementsolver.hpp | 41 ------ apps/openmw/mwworld/physicssystem.cpp | 152 +++++++++++++++++++ apps/openmw/mwworld/physicssystem.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 21 +++ 9 files changed, 184 insertions(+), 229 deletions(-) delete mode 100644 apps/openmw/mwmechanics/movementsolver.cpp delete mode 100644 apps/openmw/mwmechanics/movementsolver.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 184a00d50..a491ea5ce 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate movementsolver + aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e01303c02..a8c05f17e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -265,6 +265,7 @@ namespace MWMechanics Ogre::Vector3 movement = iter->second.update(duration); mMovement.push_back(std::make_pair(iter->first, movement)); } + MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration); mMovement.clear(); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 27c1dc851..3899b05ab 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -29,8 +29,6 @@ #include "../mwworld/class.hpp" -#include "movementsolver.hpp" - namespace MWMechanics { @@ -79,7 +77,6 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) : mPtr(ptr), mAnimation(anim), mState(state), mSkipAnim(false) { - mMovementSolver = new MovementSolver(); if(!mAnimation) return; @@ -98,7 +95,6 @@ CharacterController::CharacterController(const CharacterController &rhs) , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) , mSkipAnim(rhs.mSkipAnim) { - mMovementSolver = new MovementSolver(); if(!mAnimation) return; /* We've been copied. Update the animation with the new controller. */ @@ -107,7 +103,6 @@ CharacterController::CharacterController(const CharacterController &rhs) CharacterController::~CharacterController() { - delete mMovementSolver; } @@ -181,21 +176,14 @@ Ogre::Vector3 CharacterController::update(float duration) } mSkipAnim = false; - if(duration > 0.0f) - { - const ESM::Position &refpos = mPtr.getRefData().getPosition(); + const ESM::Position &refpos = mPtr.getRefData().getPosition(); + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - - Ogre::Vector3 res = mMovementSolver->move(mPtr, movement, duration); - MWBase::Environment::get().getWorld()->moveObject(mPtr, res.x, res.y, res.z); - } - - return Ogre::Vector3(0.0f); + return movement; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index efd90ca19..adb6364a0 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -13,8 +13,6 @@ namespace MWRender namespace MWMechanics { -class MovementSolver; - enum CharacterState { CharState_Idle, CharState_Idle2, @@ -51,8 +49,6 @@ class CharacterController CharacterState mState; bool mSkipAnim; - MovementSolver *mMovementSolver; - protected: /* Called by the animation whenever a new text key is reached. */ void markerEvent(float time, const std::string &evt); diff --git a/apps/openmw/mwmechanics/movementsolver.cpp b/apps/openmw/mwmechanics/movementsolver.cpp deleted file mode 100644 index 544cb2ab8..000000000 --- a/apps/openmw/mwmechanics/movementsolver.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "movementsolver.hpp" - -#include "libs/openengine/bullet/trace.h" -#include "libs/openengine/bullet/physic.hpp" - -#include "../mwworld/ptr.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -#include - - -namespace MWMechanics -{ - -static const float sMaxSlope = 45.0f; - -MovementSolver::MovementSolver() - : mEngine(MWBase::Environment::get().getWorld()->getPhysicEngine()) -{ -} - -MovementSolver::~MovementSolver() -{ - // nothing to do -} - -void MovementSolver::clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) -{ - //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. - //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. - float backoff; - - backoff = in.dotProduct(normal); - if(backoff < 0.0f) - backoff *= overbounce; - else - backoff /= overbounce; - - out = in - (normal*backoff); -} - -void MovementSolver::projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) -{ - Ogre::Vector3 normalizedDirection(direction); - normalizedDirection.normalise(); - - // no divide by normalizedDirection.length necessary because it's normalized - velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); -} - -bool MovementSolver::stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior) -{ - traceResults trace; // no initialization needed - - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), - position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, - halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) - return false; - - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, mEngine); - if(getSlope(trace.planenormal) < sMaxSlope) - { - // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. - position = trace.endpos; - return true; - } - - return false; -} - -float MovementSolver::getSlope(const Ogre::Vector3 &normal) -{ - return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); -} - - -Ogre::Vector3 MovementSolver::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) -{ - Ogre::Vector3 position(ptr.getRefData().getPosition().pos); - - /* Anything to collide with? */ - OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(ptr.getRefData().getHandle()); - if(!physicActor || !physicActor->getCollisionMode()) - return position + movement; - - traceResults trace; //no initialization needed - int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - - float verticalVelocity = physicActor->getVerticalForce(); - Ogre::Vector3 horizontalVelocity = movement/time; - Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps - Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); - - float remainingTime = time; - bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); - Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); - - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); - Ogre::Vector3 newPosition = position; - - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, mEngine); - if(trace.fraction < 1.0f) - { - if(getSlope(trace.planenormal) > sMaxSlope) - { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); - } - } - - do { - // trace to where character would go if there were no obstructions - newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, mEngine); - newPosition = trace.endpos; - currentNormal = trace.planenormal; - remainingTime = remainingTime * (1.0f-trace.fraction); - - // check for obstructions - if(trace.fraction != 1.0f) - { - //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) - { - if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, mEngine)) - std::cout<< "stepped" <setVerticalForce(verticalVelocity); - - return newPosition; -} - -} diff --git a/apps/openmw/mwmechanics/movementsolver.hpp b/apps/openmw/mwmechanics/movementsolver.hpp deleted file mode 100644 index 1c56df036..000000000 --- a/apps/openmw/mwmechanics/movementsolver.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef GAME_MWMECHANICS_MOVEMENTSOLVER_H -#define GAME_MWMECHANICS_MOVEMENTSOLVER_H - -#include - -namespace MWWorld -{ - class Ptr; -} - -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - -namespace MWMechanics -{ - class MovementSolver - { - public: - MovementSolver(); - virtual ~MovementSolver(); - - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); - - private: - bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior); - - void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce); - void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction); - - float getSlope(const Ogre::Vector3 &normal); - - OEngine::Physic::PhysicEngine *mEngine; - }; -} - -#endif /* GAME_MWMECHANICS_MOVEMENTSOLVER_H */ diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c95abc5a0..2d83c9a04 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -21,6 +21,153 @@ using namespace Ogre; namespace MWWorld { + static const float sMaxSlope = 45.0f; + + class MovementSolver + { + private: + static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, + float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior, + OEngine::Physic::PhysicEngine *engine) + { + traceResults trace; // no initialization needed + + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), + position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) + return false; + + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, engine); + if(getSlope(trace.planenormal) < sMaxSlope) + { + // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. + position = trace.endpos; + return true; + } + + return false; + } + + static void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, + const float overbounce) + { + //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. + //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. + float backoff; + + backoff = in.dotProduct(normal); + if(backoff < 0.0f) + backoff *= overbounce; + else + backoff /= overbounce; + + out = in - (normal*backoff); + } + + static void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) + { + Ogre::Vector3 normalizedDirection(direction); + normalizedDirection.normalise(); + + // no divide by normalizedDirection.length necessary because it's normalized + velocity = normalizedDirection * velocity.dotProduct(normalizedDirection); + } + + static float getSlope(const Ogre::Vector3 &normal) + { + return normal.angleBetween(Ogre::Vector3(0.0f,0.0f,1.0f)).valueDegrees(); + } + + public: + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, + OEngine::Physic::PhysicEngine *engine) + { + Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + + /* Anything to collide with? */ + OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); + if(!physicActor || !physicActor->getCollisionMode()) + return position + movement; + + traceResults trace; //no initialization needed + int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + + float verticalVelocity = physicActor->getVerticalForce(); + Ogre::Vector3 horizontalVelocity = movement/time; + Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); + + float remainingTime = time; + bool isInterior = !ptr.getCell()->isExterior(); + float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); + Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); + + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f) + { + if(getSlope(trace.planenormal) > sMaxSlope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } + } + + do { + // trace to where character would go if there were no obstructions + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); + newPosition = trace.endpos; + currentNormal = trace.planenormal; + remainingTime = remainingTime * (1.0f-trace.fraction); + + // check for obstructions + if(trace.fraction != 1.0f) + { + //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + { + if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + std::cout<< "stepped" <setVerticalForce(verticalVelocity); + + return newPosition; + } + }; + + PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { @@ -185,6 +332,11 @@ namespace MWWorld } } + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) + { + return MovementSolver::move(ptr, movement, time, mEngine); + } + void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 06b29d290..d897c78e9 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -35,6 +35,8 @@ namespace MWWorld bool toggleCollisionMode(); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); + std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d900f555c..fb31c54ab 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -836,6 +836,27 @@ namespace MWWorld void World::doPhysics(const PtrMovementList &actors, float duration) { + /* No duration? Shouldn't be any movement, then. */ + if(duration <= 0.0f) + return; + + PtrMovementList::const_iterator player(actors.end()); + for(PtrMovementList::const_iterator iter(actors.begin());iter != actors.end();iter++) + { + if(iter->first.getRefData().getHandle() == "player") + { + /* Handle player last, in case a cell transition occurs */ + player = iter; + continue; + } + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration); + moveObjectImp(iter->first, vec.x, vec.y, vec.z); + } + if(player != actors.end()) + { + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration); + moveObjectImp(player->first, vec.x, vec.y, vec.z); + } } bool World::toggleCollisionMode() From f7f1adfb9d6265d95804c3df2793e47aeed5280d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 12:55:06 -0800 Subject: [PATCH 542/916] Don't accumulate animations with activators --- apps/openmw/mwmechanics/character.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3899b05ab..42ab78d4f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -83,9 +83,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); getStateInfo(mState, &mCurrentGroup); - /* Accumulate along X/Y only for now, until we can figure out how we should - * handle knockout and death which moves the character down. */ - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + if(ptr.getTypeName() == typeid(ESM::Activator).name()) + { + /* Don't accumulate with activators (they don't get moved). */ + mAnimation->setAccumulation(Ogre::Vector3::ZERO); + } + else + { + /* Accumulate along X/Y only for now, until we can figure out how we should + * handle knockout and death which moves the character down. */ + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + } if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", loop); } From 347a734364fa28e045bc1809b3e0a9ca540ca870 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Tue, 5 Feb 2013 22:06:36 +0100 Subject: [PATCH 543/916] Move OpenDialog to editor and use it in startup dialogue. Remove debug output from DataFilesList. --- apps/opencs/editor.cpp | 32 +++++++++++----------- apps/opencs/editor.hpp | 3 ++ apps/opencs/view/doc/view.cpp | 29 ++------------------ apps/opencs/view/doc/view.hpp | 5 ---- components/fileorderlist/datafileslist.cpp | 2 -- 5 files changed, 21 insertions(+), 50 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 7156db94e..02b494d3d 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -15,6 +15,8 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); + + connect (&mOpenDialog, SIGNAL(accepted()), this, SLOT(openFiles())); } void CS::Editor::createDocument() @@ -36,26 +38,24 @@ void CS::Editor::createDocument() } void CS::Editor::loadDocument() +{ + mOpenDialog.show(); + mOpenDialog.raise(); + mOpenDialog.activateWindow(); +} + +void CS::Editor::openFiles() { mStartup.hide(); - - /// \todo open the ESX picker instead - /// \todo remove the manual record creation and load the ESX files instead - - std::ostringstream stream; - - stream << "Document" << (++mNewDocumentIndex); - - std::vector files; - files.push_back (stream.str()); - - CSMDoc::Document *document = mDocumentManager.addDocument (files, false); - + std::vector paths; + mOpenDialog.getFileList(paths); + CSMDoc::Document *document = mDocumentManager.addDocument(paths, false); + static const char *sGlobals[] = { "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 }; - + for (int i=0; sGlobals[i]; ++i) { ESM::Global record; @@ -64,9 +64,9 @@ void CS::Editor::loadDocument() record.mType = ESM::VT_Float; document->getData().getGlobals().add (record); } - + document->getData().merge(); /// \todo remove once proper ESX loading is implemented - + mViewManager.addView (document); } diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 0cd780f7f..024475bf0 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -7,6 +7,7 @@ #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" +#include "view/doc/opendialog.hpp" namespace CS { @@ -19,6 +20,7 @@ namespace CS CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; + OpenDialog mOpenDialog; // not implemented Editor (const Editor&); @@ -36,6 +38,7 @@ namespace CS void createDocument(); void loadDocument(); + void openFiles(); }; } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 146e6634e..f5cc3d85b 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -14,7 +14,6 @@ #include "../tools/subviews.hpp" -#include "opendialog.hpp" #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" @@ -32,12 +31,8 @@ void CSVDoc::View::setupFileMenu() QAction *new_ = new QAction (tr ("New"), this); connect (new_, SIGNAL (triggered()), this, SIGNAL (newDocumentRequest())); file->addAction (new_); - - mOpen = new QAction(tr ("&Open"), this); - connect (mOpen, SIGNAL (triggered()), this, SLOT (open())); - file->addAction (mOpen); - QAction *open = new QAction (tr ("Open"), this); + QAction *open = new QAction (tr ("&Open"), this); connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest())); file->addAction (open); @@ -119,7 +114,7 @@ void CSVDoc::View::updateActions() } CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) -: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), mOpenDialog(0) +: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { setDockOptions (QMainWindow::AllowNestedDocks); @@ -214,26 +209,6 @@ void CSVDoc::View::save() mDocument->save(); } -void CSVDoc::View::open() -{ - if (!mOpenDialog) { - mOpenDialog = new OpenDialog(this); - connect(mOpenDialog, SIGNAL(accepted()), this, SLOT(openNewFiles())); - } - - mOpenDialog->show(); - mOpenDialog->raise(); - mOpenDialog->activateWindow(); -} - -void CSVDoc::View::openNewFiles() -{ - std::vector paths; - mOpenDialog->getFileList(paths); - //FIXME load new files - -} - void CSVDoc::View::verify() { addSubView (mDocument->verify()); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index bb3763bb9..05d7210dc 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -9,7 +9,6 @@ #include "subviewfactory.hpp" class QAction; -class OpenDialog; namespace CSMDoc { @@ -37,12 +36,10 @@ namespace CSVDoc QAction *mUndo; QAction *mRedo; QAction *mSave; - QAction *mOpen; QAction *mVerify; std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; - OpenDialog * mOpenDialog; // not implemented View (const View&); @@ -97,8 +94,6 @@ namespace CSVDoc void newView(); - void open(); - void openNewFiles(); void save(); void verify(); diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index 38e0bfb1a..d25060baa 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -204,13 +204,11 @@ void DataFilesList::selectedFiles(std::vector& paths) foreach (const QString &path, masterPaths) { paths.push_back(path.toStdString()); - cerr << path.toStdString() << endl; } QStringList pluginPaths = mPluginsModel->checkedItemsPaths(); foreach (const QString &path, pluginPaths) { paths.push_back(path.toStdString()); - cerr << path.toStdString() << endl; } } From 8c0bb1ff4d26567ff4eb1a96a5e70e0f9c5ec227 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 14:02:14 -0800 Subject: [PATCH 544/916] Rotate movement in the movement solver --- apps/openmw/mwmechanics/character.cpp | 7 ------- apps/openmw/mwworld/physicssystem.cpp | 11 +++++++++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 42ab78d4f..f1f6280e5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -184,13 +184,6 @@ Ogre::Vector3 CharacterController::update(float duration) } mSkipAnim = false; - const ESM::Position &refpos = mPtr.getRefData().getPosition(); - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - return movement; } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 2d83c9a04..7020c8fb2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -80,10 +80,17 @@ namespace MWWorld } public: - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, OEngine::Physic::PhysicEngine *engine) { - Ogre::Vector3 position(ptr.getRefData().getPosition().pos); + const ESM::Position &refpos = ptr.getRefData().getPosition(); + Ogre::Vector3 position(refpos.pos); + + // Rotates first around z, then y, then x + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * + movement; /* Anything to collide with? */ OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); From 86d65519e370041b7b9422bb85a188eadba96c56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Feb 2013 23:57:30 +0100 Subject: [PATCH 545/916] Settings window fix --- apps/openmw/mwgui/settingswindow.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 75fc2b7a2..eaea022c0 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -247,10 +247,10 @@ namespace MWGui mInvertYButton->setCaptionWithReplacing(Settings::Manager::getBool("invert y axis", "Input") ? "#{sOn}" : "#{sOff}"); - mShadersButton->setCaption (Settings::Manager::getBool("shaders", "Objects") ? "on" : "off"); + mShadersButton->setCaptionWithReplacing (Settings::Manager::getBool("shaders", "Objects") ? "#{sOn}" : "#{sOff}"); mShaderModeButton->setCaption (Settings::Manager::getString("shader mode", "General")); - mRefractionButton->setCaption (Settings::Manager::getBool("refraction", "Water") ? "on" : "off"); + mRefractionButton->setCaptionWithReplacing (Settings::Manager::getBool("refraction", "Water") ? "#{sOn}" : "#{sOff}"); if (!MWRender::RenderingManager::waterShaderSupported()) { @@ -434,14 +434,17 @@ namespace MWGui void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) { - std::string val = static_cast(_sender)->getCaption(); - if (val == "off") - val = "on"; - else - val = "off"; - static_cast(_sender)->setCaption (val); + std::string on = mWindowManager.getGameSettingString("sOn", "On"); + std::string off = mWindowManager.getGameSettingString("sOff", "On"); - if (val == "off") + std::string val = static_cast(_sender)->getCaption(); + if (val == off) + val = on; + else + val = off; + static_cast(_sender)->setCaptionWithReplacing (val); + + if (val == off) { Settings::Manager::setBool("shaders", "Objects", false); From ee3764e9b34c1da280fc48a65a08225ffca0060f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 15:07:48 -0800 Subject: [PATCH 546/916] Increase max slope to 60. 45 is too low. --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7020c8fb2..9517715b6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -21,7 +21,7 @@ using namespace Ogre; namespace MWWorld { - static const float sMaxSlope = 45.0f; + static const float sMaxSlope = 60.0f; class MovementSolver { From 6e3c016351ed60c3b029d5e6b5ae605be6883685 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 3 Feb 2013 17:42:58 +0100 Subject: [PATCH 547/916] Add archives to settings imported by mwiniimporter Add Morrowind.bsa by default. --- apps/mwiniimporter/importer.cpp | 33 +++++++++++++++++++++++++++++++++ apps/mwiniimporter/importer.hpp | 1 + apps/mwiniimporter/main.cpp | 5 +++++ 3 files changed, 39 insertions(+) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 077b62be1..87a87f630 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -777,6 +777,39 @@ void MwIniImporter::insertMultistrmap(multistrmap &cfg, std::string key, std::st cfg[key].push_back(value); } +void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) { + std::vector archives; + std::string baseArchive("Archives:Archive "); + std::string archive; + + // Search archives listed in ini file + multistrmap::iterator it = ini.begin(); + for(int i=0; it != ini.end(); i++) { + archive = baseArchive; + archive.append(this->numberToString(i)); + + it = ini.find(archive); + if(it == ini.end()) { + break; + } + + for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { + archives.push_back(*entry); + } + } + + cfg.erase("fallback-archive"); + cfg.insert( std::make_pair > ("fallback-archive", std::vector())); + + // Add Morrowind.bsa by default, since Vanilla loads this archive even if it + // does not appears in the ini file + cfg["fallback-archive"].push_back("Morrowind.bsa"); + + for(std::vector::iterator it=archives.begin(); it!=archives.end(); ++it) { + cfg["fallback-archive"].push_back(*it); + } +} + void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { std::vector esmFiles; std::vector espFiles; diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index c87fd3e16..6b99810bc 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -23,6 +23,7 @@ class MwIniImporter { void merge(multistrmap &cfg, multistrmap &ini); void mergeFallback(multistrmap &cfg, multistrmap &ini); void importGameFiles(multistrmap &cfg, multistrmap &ini); + void importArchives(multistrmap &cfg, multistrmap &ini); void writeToFile(boost::iostreams::stream &out, multistrmap &cfg); private: diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index e90f26dd2..c9d88c0bb 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -18,6 +18,7 @@ int main(int argc, char *argv[]) { ("cfg,c", bpo::value(), "openmw.cfg file") ("output,o", bpo::value()->default_value(""), "openmw.cfg file") ("game-files,g", "import esm and esp files") + ("no-archives,A", "disable bsa archives import") ("encoding,e", bpo::value()-> default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n" @@ -76,6 +77,10 @@ int main(int argc, char *argv[]) { importer.importGameFiles(cfg, ini); } + if(!vm.count("no-archives")) { + importer.importArchives(cfg, ini); + } + std::cout << "write to: " << outputFile << std::endl; boost::iostreams::stream file(outputFile); importer.writeToFile(file, cfg); From a4f051e85a9e423b94759136db60753addc435ca Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 5 Feb 2013 20:38:15 +0100 Subject: [PATCH 548/916] Fix game files import --- apps/mwiniimporter/importer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 87a87f630..fc9ce417c 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -827,7 +827,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { } for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { - std::string filetype(entry->substr(entry->length()-4, 3)); + std::string filetype(entry->substr(entry->length()-3)); Misc::StringUtils::toLower(filetype); if(filetype.compare("esm") == 0) { From e217a3d25c1a7720d672ce748186db3ab09832ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 15:51:26 -0800 Subject: [PATCH 549/916] Silence some console spam --- apps/openmw/mwworld/physicssystem.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9517715b6..e6e4dd676 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -143,9 +143,7 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) - std::cout<< "stepped" < Date: Tue, 5 Feb 2013 16:29:51 -0800 Subject: [PATCH 550/916] Use a vector of skeletons to handle animation sources --- apps/openmw/mwrender/animation.cpp | 96 ++++++++++++++++++++---------- apps/openmw/mwrender/animation.hpp | 5 ++ 2 files changed, 69 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0e906181c..ad98efb14 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,6 +46,42 @@ Animation::~Animation() } +Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) +{ + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + Ogre::SkeletonPtr skel = skelMgr.getByName(name); + if(skel.isNull()) + { + std::cerr<< "Failed to get skeleton source "<touch(); + mSkeletonSources.push_back(skel); + + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty() || !Ogre::any_cast(data)) + continue; + + for(int i = 0;i < skel->getNumAnimations();i++) + { + Ogre::Animation *anim = skel->getAnimation(i); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+anim->getName()); + if(!groupdata.isEmpty()) + mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + } + + return bone; + } + + return NULL; +} + void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) { mInsert = node->createChildSceneNode(); @@ -63,51 +99,35 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model state->setLoop(false); } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); - // Would be nice if Ogre::SkeletonInstance allowed access to the 'master' Ogre::SkeletonPtr. - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(skelinst->getName()); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; + boneiter.getNext()->setManuallyControlled(true); + Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); + if(bone) + { mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getHandle()); mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; - - asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+state->getAnimationName()); - if(!groupdata.isEmpty()) - mTextKeys[state->getAnimationName()] = Ogre::any_cast(groupdata); - } - - break; } - - // Set the bones as manually controlled since we're applying the - // transformations manually (needed if we want to apply an animation - // from one skeleton onto another). - boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); } } bool Animation::hasAnimation(const std::string &anim) { - return mEntityList.mSkelBase && mEntityList.mSkelBase->getSkeleton()->hasAnimation(anim); + for(std::vector::const_iterator iter(mSkeletonSources.begin());iter != mSkeletonSources.end();iter++) + { + if((*iter)->hasAnimation(anim)) + return true; + } + return false; } @@ -208,8 +228,20 @@ void Animation::reset(const std::string &marker) void Animation::play(const std::string &groupname, const std::string &start, bool loop) { try { - mCurrentAnim = mEntityList.mSkelBase->getSkeleton()->getAnimation(groupname); - mCurrentKeys = &mTextKeys[groupname]; + bool found = false; + /* Look in reverse; last-inserted source has priority. */ + for(std::vector::const_reverse_iterator iter(mSkeletonSources.rbegin());iter != mSkeletonSources.rend();iter++) + { + if((*iter)->hasAnimation(groupname)) + { + mCurrentAnim = (*iter)->getAnimation(groupname); + mCurrentKeys = &mTextKeys[groupname]; + found = true; + break; + } + } + if(!found) + throw std::runtime_error("Failed to find animation "+groupname); reset(start); mPlaying = true; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 46a1ed88d..62e93f110 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -28,6 +28,8 @@ protected: Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; + std::vector mSkeletonSources; + NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; @@ -53,6 +55,9 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); + /* Inserts an additional skeleton into the animation source chain. Returns + * the bone representing the non-accum root from the base skeleton. */ + Ogre::Bone *insertSkeletonSource(const std::string &name); void createEntityList(Ogre::SceneNode *node, const std::string &model); From 16933e3926c368a575ee39e10d58cd65247c2d3a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 16:59:20 -0800 Subject: [PATCH 551/916] Scale the accumulation root translation --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ad98efb14..63bd07bee 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -196,7 +196,7 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff); + mAccumRoot->translate(-posdiff * mAccumRoot->_getDerivedScale()); mLastPosition += posdiff; } return posdiff; @@ -220,7 +220,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(mStartPosition - mLastPosition); + mAccumRoot->setPosition((mStartPosition - mLastPosition) * mAccumRoot->_getDerivedScale()); } } From 054ef3113a8c28fd3cd59c19a60309d4cd1098ea Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:15:40 -0800 Subject: [PATCH 552/916] Check existing skeleton sources if the current one has no animation root --- apps/openmw/mwrender/animation.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 63bd07bee..baca70e37 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -108,10 +108,28 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model boneiter.getNext()->setManuallyControlled(true); Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); + if(!bone) + { + for(std::vector::const_iterator iter(mSkeletonSources.begin()); + !bone && iter != mSkeletonSources.end();iter++) + { + Ogre::Skeleton::BoneIterator boneiter = (*iter)->getBoneIterator(); + while(boneiter.hasMoreElements()) + { + bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(!data.isEmpty() && Ogre::any_cast(data)) + break; + + bone = NULL; + } + } + } if(bone) { mAccumRoot = mInsert; - mNonAccumRoot = skelinst->getBone(bone->getHandle()); + mNonAccumRoot = skelinst->getBone(bone->getName()); mStartPosition = mNonAccumRoot->getInitialPosition(); mLastPosition = mStartPosition; From c839502743697f9caa67ee60aec8e90e6f47f6d0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:16:45 -0800 Subject: [PATCH 553/916] Setup base_anim.nif as an initial skeleton source for biped creatures --- apps/openmw/mwrender/creatureanimation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 34b09c0d0..094281c46 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -23,9 +23,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->mBase->mModel; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + insertSkeletonSource("meshes\\base_anim.nif"); - createEntityList(mPtr.getRefData().getBaseNode(), mesh); + createEntityList(mPtr.getRefData().getBaseNode(), "meshes\\"+ref->mBase->mModel); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; From 8b1e7b95ba4637cf01b65a1254f3e76b0cd55c77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 17:55:12 -0800 Subject: [PATCH 554/916] Attempt to load the skeleton source if it doesn't yet exist --- apps/openmw/mwrender/animation.cpp | 9 +++++++-- components/nifogre/ogre_nif_loader.cpp | 27 ++++++++++++++++++++++++++ components/nifogre/ogre_nif_loader.hpp | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index baca70e37..f0ba8d654 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -52,8 +52,13 @@ Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) Ogre::SkeletonPtr skel = skelMgr.getByName(name); if(skel.isNull()) { - std::cerr<< "Failed to get skeleton source "<touch(); mSkeletonSources.push_back(skel); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b878c29f4..c7f6ac50d 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1250,6 +1250,33 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } +bool Loader::createSkeleton(const std::string &name, const std::string &group) +{ + Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); + Nif::NIFFile &nif = *pnif.get(); + if(nif.numRecords() < 1) + { + nif.warn("Found no NIF records in "+name+"."); + return false; + } + + // The first record is assumed to be the root node + Nif::Record const *r = nif.getRecord(0); + assert(r != NULL); + + Nif::Node const *node = dynamic_cast(r); + if(node == NULL) + { + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return false; + } + + NIFSkeletonLoader skelldr; + return skelldr.createSkeleton(name, group, node); +} + + /* More code currently not in use, from the old D source. This was used in the first attempt at loading NIF meshes, where each submesh in the file was given a separate bone in a skeleton. Unfortunately diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 12be52233..0064defe2 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -77,6 +77,8 @@ public: static EntityList createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); + + static bool createSkeleton(const std::string &name, const std::string &group="General"); }; } From 535cd8360fd49ac805b7574529267e20559bbfb6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 18:09:43 -0800 Subject: [PATCH 555/916] Load extra animations for NPCs --- apps/openmw/mwrender/npcanimation.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 18f44c87c..74b3945fa 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -120,6 +120,14 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + if(!mNpc->isMale() && !isBeast) + insertSkeletonSource("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + insertSkeletonSource("meshes\\argonian_swimkna.nif"); + + if(mNpc->mModel.length() > 0) + insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + float scale = race->mData.mHeight.mMale; if (!mNpc->isMale()) { scale = race->mData.mHeight.mFemale; From 18b70084095facb95a25011a891f167f6a9966cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 18:25:09 -0800 Subject: [PATCH 556/916] Better fix some scaling issues --- apps/openmw/mwrender/animation.cpp | 4 ++-- apps/openmw/mwrender/npcanimation.cpp | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f0ba8d654..019217ca6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -219,7 +219,7 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff * mAccumRoot->_getDerivedScale()); + mAccumRoot->translate(-posdiff); mLastPosition += posdiff; } return posdiff; @@ -243,7 +243,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition((mStartPosition - mLastPosition) * mAccumRoot->_getDerivedScale()); + mAccumRoot->setPosition(mStartPosition*mNonAccumRoot->_getDerivedScale() - mLastPosition); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 74b3945fa..120996a70 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -83,6 +83,11 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); + float scale = race->mData.mHeight.mMale; + if(!mNpc->isMale()) + scale = race->mData.mHeight.mFemale; + node->scale(Ogre::Vector3(scale)); + mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; @@ -128,12 +133,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor if(mNpc->mModel.length() > 0) insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - float scale = race->mData.mHeight.mMale; - if (!mNpc->isMale()) { - scale = race->mData.mHeight.mFemale; - } - mInsert->scale(scale, scale, scale); - updateParts(); } From fc307e64b03d47e38f91cdcb4ac181f7fdfb0d6d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 19:05:07 -0800 Subject: [PATCH 557/916] Add swimming states --- apps/openmw/mwmechanics/character.cpp | 18 +++++++++++++----- apps/openmw/mwmechanics/character.hpp | 6 ++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f1f6280e5..f119ceb69 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -46,12 +46,18 @@ static const struct { { CharState_Idle7, "idle7" }, { CharState_Idle8, "idle8" }, { CharState_Idle9, "idle9" }, + { CharState_IdleSwim, "idleswim" }, { CharState_WalkForward, "walkforward" }, { CharState_WalkBack, "walkback" }, { CharState_WalkLeft, "walkleft" }, { CharState_WalkRight, "walkright" }, + { CharState_SwimWalkForward, "swimwalkforward" }, + { CharState_SwimWalkBack, "swimwalkback" }, + { CharState_SwimWalkLeft, "swimwalkleft" }, + { CharState_SwimWalkRight, "swimwalkright" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -157,21 +163,23 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) - setState(CharState_WalkRight, true); + setState((inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); else if(vec.x < 0.0f) - setState(CharState_WalkLeft, true); + setState((inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); } else if(vec.y > 0.0f) - setState(CharState_WalkForward, true); + setState((inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); else if(vec.y < 0.0f) - setState(CharState_WalkBack, true); + setState((inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) - setState(CharState_Idle, true); + setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } Ogre::Vector3 movement = Ogre::Vector3::ZERO; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index adb6364a0..535680fa1 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -23,12 +23,18 @@ enum CharacterState { CharState_Idle7, CharState_Idle8, CharState_Idle9, + CharState_IdleSwim, CharState_WalkForward, CharState_WalkBack, CharState_WalkLeft, CharState_WalkRight, + CharState_SwimWalkForward, + CharState_SwimWalkBack, + CharState_SwimWalkLeft, + CharState_SwimWalkRight, + /* Must be last! */ CharState_Death1, CharState_Death2, From 9cf30f39bd1d3b1c17450d2929c75e98b76318de Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 5 Feb 2013 19:45:51 -0800 Subject: [PATCH 558/916] Don't apply gravity when swimming --- apps/openmw/mwworld/physicssystem.cpp | 32 +++++++++++++++------------ apps/openmw/mwworld/physicssystem.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index e6e4dd676..b30d9a7b2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -81,7 +81,7 @@ namespace MWWorld public: static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, - OEngine::Physic::PhysicEngine *engine) + bool gravity, OEngine::Physic::PhysicEngine *engine) { const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); @@ -100,8 +100,9 @@ namespace MWWorld traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - float verticalVelocity = physicActor->getVerticalForce(); Ogre::Vector3 horizontalVelocity = movement/time; + float verticalVelocity = (gravity ? physicActor->getVerticalForce() : + horizontalVelocity.z); Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); @@ -115,18 +116,21 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f) + if(gravity) { - if(getSlope(trace.planenormal) > sMaxSlope) + newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f) { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + if(getSlope(trace.planenormal) > sMaxSlope) + { + // if we're on a really steep slope, don't listen to user input + clippedVelocity.x = clippedVelocity.y = 0.0f; + } + else + { + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + } } } @@ -339,9 +343,9 @@ namespace MWWorld } } - Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time) + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity) { - return MovementSolver::move(ptr, movement, time, mEngine); + return MovementSolver::move(ptr, movement, time, gravity, mEngine); } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index d897c78e9..c1f70f2ca 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -35,7 +35,7 @@ namespace MWWorld bool toggleCollisionMode(); - Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time); + Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fb31c54ab..b59907683 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -849,12 +849,12 @@ namespace MWWorld player = iter; continue; } - Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration); + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, !isSwimming(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { - Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration); + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } } From dfd16c44245c6577fca1e05522974fbdb9a6bde5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 12:39:26 -0800 Subject: [PATCH 559/916] Fix movement rotations --- apps/openmw/mwworld/physicssystem.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b30d9a7b2..c42214fb2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -86,20 +86,33 @@ namespace MWWorld const ESM::Position &refpos = ptr.getRefData().getPosition(); Ogre::Vector3 position(refpos.pos); - // Rotates first around z, then y, then x - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[0]), Ogre::Vector3::UNIT_X)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)) * - movement; - /* Anything to collide with? */ OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); if(!physicActor || !physicActor->getCollisionMode()) - return position + movement; + { + // FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why? + return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement; + } traceResults trace; //no initialization needed int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + if(!gravity) + { + movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement; + } + else + { + movement = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * + movement; + } + Ogre::Vector3 horizontalVelocity = movement/time; float verticalVelocity = (gravity ? physicActor->getVerticalForce() : horizontalVelocity.z); From bdda7278c4acf52b9d23950d64314d39d3f86f2a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 12:56:30 -0800 Subject: [PATCH 560/916] Use 3/4ths of the physic actor's height to test if swimming --- apps/openmw/mwworld/worldimp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b59907683..55270280d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1336,8 +1336,9 @@ namespace MWWorld float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - /// \fixme should rely on object height - pos.z += 30; + /// \fixme 3/4ths submerged? + const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); + if(actor) pos.z += actor->getHalfExtents().z * 1.5; return isUnderwater(*object.getCell()->mCell, pos); } From 04524fbf92fd639751daf75a0724b6aed9881249 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 15:23:52 -0800 Subject: [PATCH 561/916] Don't scale the movement vector up --- apps/openmw/mwclass/npc.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6069e3b7c..3666d9d6b 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -311,14 +311,10 @@ namespace MWClass Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const { - Ogre::Vector3 vector (0, 0, 0); - - vector.x = getMovementSettings (ptr).mLeftRight * 127; - vector.y = getMovementSettings (ptr).mForwardBackward * 127; - vector.z = getMovementSettings(ptr).mUpDown * 127; - - //if (getStance (ptr, Run, false)) - // vector *= 2; + Ogre::Vector3 vector; + vector.x = getMovementSettings(ptr).mLeftRight; + vector.y = getMovementSettings(ptr).mForwardBackward; + vector.z = getMovementSettings(ptr).mUpDown; return vector; } From cbaf489eb6436681d4cb2893749f68a9d4510009 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 16:53:52 -0800 Subject: [PATCH 562/916] Add running states --- apps/openmw/mwmechanics/character.cpp | 27 +++++++++++++++++++++++---- apps/openmw/mwmechanics/character.hpp | 10 ++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f119ceb69..b6e96bdf5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -58,6 +58,16 @@ static const struct { { CharState_SwimWalkLeft, "swimwalkleft" }, { CharState_SwimWalkRight, "swimwalkright" }, + { CharState_RunForward, "runforward" }, + { CharState_RunBack, "runback" }, + { CharState_RunLeft, "runleft" }, + { CharState_RunRight, "runright" }, + + { CharState_SwimRunForward, "swimrunforward" }, + { CharState_SwimRunBack, "swimrunback" }, + { CharState_SwimRunLeft, "swimrunleft" }, + { CharState_SwimRunRight, "swimrunright" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -164,18 +174,27 @@ Ogre::Vector3 CharacterController::update(float duration) const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); if(std::abs(vec.x/2.0f) > std::abs(vec.y)) { if(vec.x > 0.0f) - setState((inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); + setState(isrunning ? + (inwater ? CharState_SwimRunRight : CharState_RunRight) : + (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); else if(vec.x < 0.0f) - setState((inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + setState(isrunning ? + (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : + (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); } else if(vec.y > 0.0f) - setState((inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); else if(vec.y < 0.0f) - setState((inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 535680fa1..d67964b84 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -35,6 +35,16 @@ enum CharacterState { CharState_SwimWalkLeft, CharState_SwimWalkRight, + CharState_RunForward, + CharState_RunBack, + CharState_RunLeft, + CharState_RunRight, + + CharState_SwimRunForward, + CharState_SwimRunBack, + CharState_SwimRunLeft, + CharState_SwimRunRight, + /* Must be last! */ CharState_Death1, CharState_Death2, From 814969dcae6ab8428b582bc86921ca38d072274e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Feb 2013 02:23:41 +0100 Subject: [PATCH 563/916] Cache integrity check uses relative paths, so that changing the build folder works without reset --- extern/shiny/Main/Factory.cpp | 99 ++++++++++++++++++++--------------- extern/shiny/Main/Factory.hpp | 2 + 2 files changed, 58 insertions(+), 43 deletions(-) diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index c63a9e367..21f13e30b 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -50,7 +50,7 @@ namespace sh { assert(mCurrentLanguage != Language_None); - bool anyShaderDirty = false; + bool removeBinaryCache = false; if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt")) { @@ -182,57 +182,33 @@ namespace sh } } - std::string sourceFile = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); + std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue(); + std::string sourceRelative = it->second->findChild("source")->getValue(); ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile, - sourceFile, + sourceAbsolute, mPlatform->getBasePath(), it->first, &mGlobalSettings); - int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceFile)); - mShadersLastModifiedNew[sourceFile] = lastModified; - if (mShadersLastModified.find(sourceFile) != mShadersLastModified.end() - && mShadersLastModified[sourceFile] != lastModified) + int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute)); + mShadersLastModifiedNew[sourceRelative] = lastModified; + if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end()) { - // delete any outdated shaders based on this shader set. - if ( boost::filesystem::exists(mPlatform->getCacheFolder()) - && boost::filesystem::is_directory(mPlatform->getCacheFolder())) + if (mShadersLastModified[sourceRelative] != lastModified) { - boost::filesystem::directory_iterator end_iter; - for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter) - { - if (boost::filesystem::is_regular_file(dir_iter->status()) ) - { - boost::filesystem::path file = dir_iter->path(); - - std::string pathname = file.filename().string(); - - // get first part of filename, e.g. main_fragment_546457654 -> main_fragment - // there is probably a better method for this... - std::vector tokens; - boost::split(tokens, pathname, boost::is_any_of("_")); - tokens.erase(--tokens.end()); - std::string shaderName; - for (std::vector::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();) - { - shaderName += *(vector_iter++); - if (vector_iter != tokens.end()) - shaderName += "_"; - } - - if (shaderName == it->first) - { - boost::filesystem::remove(file); - std::cout << "Removing outdated file: " << file << std::endl; - } - } - } + // delete any outdated shaders based on this shader set + removeCache (it->first); + // remove the whole binary cache (removing only the individual shaders does not seem to be possible at this point with OGRE) + removeBinaryCache = true; } - - anyShaderDirty = true; } - + else + { + // if we get here, this is either the first run or a new shader file was added + // in both cases we can safely delete + removeCache (it->first); + } mShaderSets.insert(std::make_pair(it->first, newSet)); } } @@ -326,7 +302,7 @@ namespace sh } } - if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !anyShaderDirty) + if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache) { std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; if (boost::filesystem::exists(file)) @@ -613,4 +589,41 @@ namespace sh assert(m); m->createForConfiguration (configuration, 0); } + + void Factory::removeCache(const std::string& pattern) + { + if ( boost::filesystem::exists(mPlatform->getCacheFolder()) + && boost::filesystem::is_directory(mPlatform->getCacheFolder())) + { + boost::filesystem::directory_iterator end_iter; + for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter) + { + if (boost::filesystem::is_regular_file(dir_iter->status()) ) + { + boost::filesystem::path file = dir_iter->path(); + + std::string pathname = file.filename().string(); + + // get first part of filename, e.g. main_fragment_546457654 -> main_fragment + // there is probably a better method for this... + std::vector tokens; + boost::split(tokens, pathname, boost::is_any_of("_")); + tokens.erase(--tokens.end()); + std::string shaderName; + for (std::vector::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();) + { + shaderName += *(vector_iter++); + if (vector_iter != tokens.end()) + shaderName += "_"; + } + + if (shaderName == pattern) + { + boost::filesystem::remove(file); + std::cout << "Removing outdated shader: " << file << std::endl; + } + } + } + } + } } diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp index 1062c079c..6d4175c97 100644 --- a/extern/shiny/Main/Factory.hpp +++ b/extern/shiny/Main/Factory.hpp @@ -202,6 +202,8 @@ namespace sh MaterialInstance* findInstance (const std::string& name); MaterialInstance* searchInstance (const std::string& name); + + void removeCache (const std::string& pattern); }; } From a8f0ce43a5e1d6f50758c8fb8663ac6082f892d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 17:51:47 -0800 Subject: [PATCH 564/916] Add a run key --- apps/openmw/mwinput/inputmanagerimp.cpp | 8 ++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ apps/openmw/mwworld/player.cpp | 6 ++++++ apps/openmw/mwworld/player.hpp | 1 + 4 files changed, 17 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 991cf4f51..4868eedae 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -301,6 +301,11 @@ namespace MWInput else mPlayer.setUpDown (0); + if(actionIsActive(A_Run)) + mPlayer.setRunState(true); + else + mPlayer.setRunState(false); + if (mControlSwitch["playerviewswitch"]) { // work around preview mode toggle when pressing Alt+Tab @@ -690,6 +695,7 @@ namespace MWInput defaultKeyBindings[A_ToggleSpell] = OIS::KC_R; defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1; defaultKeyBindings[A_Console] = OIS::KC_F2; + defaultKeyBindings[A_Run] = OIS::KC_LSHIFT; defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL; defaultKeyBindings[A_AutoMove] = OIS::KC_Q; defaultKeyBindings[A_Jump] = OIS::KC_E; @@ -756,6 +762,7 @@ namespace MWInput descriptions[A_ToggleWeapon] = "sReady_Weapon"; descriptions[A_ToggleSpell] = "sReady_Magic"; descriptions[A_Console] = "sConsoleTitle"; + descriptions[A_Run] = "sRun"; descriptions[A_Crouch] = "sCrouch_Sneak"; descriptions[A_AutoMove] = "sAuto_Run"; descriptions[A_Jump] = "sJump"; @@ -804,6 +811,7 @@ namespace MWInput ret.push_back(A_MoveLeft); ret.push_back(A_MoveRight); ret.push_back(A_TogglePOV); + ret.push_back(A_Run); ret.push_back(A_Crouch); ret.push_back(A_Activate); ret.push_back(A_ToggleWeapon); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f28..6fd6441da 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -239,6 +239,8 @@ namespace MWInput A_ToggleHUD, + A_Run, + A_Last // Marker for the last item }; }; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 3414ba448..76d44a5d7 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -71,6 +71,12 @@ namespace MWWorld MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value; } + void Player::setRunState(bool run) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).setStance(ptr, MWWorld::Class::Run, run); + } + void Player::toggleRunning() { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 1c1ef76cf..4ef4d6771 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -65,6 +65,7 @@ namespace MWWorld void setForwardBackward (int value); void setUpDown(int value); + void setRunState(bool run); void toggleRunning(); }; } From ebc7bc9427da101a1b71223706d74fde1a56a845 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 18:22:16 -0800 Subject: [PATCH 565/916] Rename A_AlwaysRun to A_Run Note that there is an "always run" key, but its functionality is handled by A_ToggleWalk. --- apps/openmw/mwinput/inputmanagerimp.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 6fd6441da..3af39911c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -207,7 +207,7 @@ namespace MWInput A_Journal, //Journal A_Weapon, //Draw/Sheath weapon A_Spell, //Ready/Unready Casting - A_AlwaysRun, //Toggle Always Run + A_Run, //Run when held A_CycleSpellLeft, //cycling through spells A_CycleSpellRight, A_CycleWeaponLeft,//Cycling through weapons @@ -239,8 +239,6 @@ namespace MWInput A_ToggleHUD, - A_Run, - A_Last // Marker for the last item }; }; From e577ee2de815d9880ab66cf208c03c6c259cec0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:44:58 -0800 Subject: [PATCH 566/916] Add a method to set/retrieve being on the ground --- apps/openmw/mwworld/physicssystem.cpp | 13 +++++++++---- apps/openmw/mwworld/worldimp.cpp | 18 +++++++----------- libs/openengine/bullet/physic.cpp | 11 ++++++++++- libs/openengine/bullet/physic.hpp | 5 +++++ 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c42214fb2..c5c634d79 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -9,6 +9,9 @@ #include #include +#include +#include + #include //#include "../mwbase/world.hpp" // FIXME @@ -129,6 +132,7 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; + bool onground = false; if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); @@ -155,10 +159,11 @@ namespace MWWorld remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions - if(trace.fraction != 1.0f) + if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + onground = getSlope(currentNormal) <= sMaxSlope; + if(!onground || currentNormal == lastNormal) { if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { @@ -184,8 +189,8 @@ namespace MWWorld } while(iterations < maxIterations && remainingTime != 0.0f); verticalVelocity = clippedVelocity.z; - verticalVelocity -= time*400; - physicActor->setVerticalForce(verticalVelocity); + physicActor->setVerticalForce(verticalVelocity - time*400.0f); + physicActor->setOnGround(onground); return newPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 55270280d..085add7c9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1,5 +1,7 @@ #include "worldimp.hpp" +#include + #include #include @@ -1366,20 +1368,14 @@ namespace MWWorld { Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); - Ogre::Vector3 playerPos; - float* pos = mPlayer->getPlayer ().getRefData ().getPosition ().pos; - playerPos.x = pos[0]; - playerPos.y = pos[1]; - playerPos.z = pos[2]; + RefData &refdata = mPlayer->getPlayer().getRefData(); + const OEngine::Physic::PhysicActor *physact = mPhysEngine->getCharacter(refdata.getHandle()); + Ogre::Vector3 playerPos(refdata.getPosition().pos); - std::pair hit = - mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); - bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); - - if (!isOnGround || isUnderwater (*currentCell->mCell, playerPos)) + if(!physact->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) return 2; - if (currentCell->mCell->mData.mFlags & ESM::Cell::NoSleep) + if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; return 0; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 1ae916f81..95313cdba 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -28,7 +28,7 @@ namespace Physic }; PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -180,6 +180,15 @@ namespace Physic return verticalForce; } + void PhysicActor::setOnGround(bool grounded) + { + onGround = grounded; + } + + bool PhysicActor::getOnGround() const + { + return collisionMode && onGround; + } void PhysicActor::runPmove(){ Pmove(pmove); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index daf1c09f2..4bc926b8a 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -132,6 +132,10 @@ namespace Physic */ float getVerticalForce() const; + void setOnGround(bool grounded); + + bool getOnGround() const; + /** * Runs pmove for this PhysicActor */ @@ -152,6 +156,7 @@ namespace Physic btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; float verticalForce; + bool onGround; bool collisionMode; std::string mMesh; PhysicEngine* mEngine; From 923d0d6eb4030cac4a1198b85a70ebcc62f58788 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:47:09 -0800 Subject: [PATCH 567/916] Fix up some header includes --- apps/openmw/mwrender/debugging.cpp | 2 ++ apps/openmw/mwrender/debugging.hpp | 9 ++++++++- apps/openmw/mwrender/objects.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwworld/physicssystem.hpp | 5 ++++- libs/openengine/bullet/pmove.cpp | 4 ++-- libs/openengine/bullet/pmove.h | 10 ++++++++-- libs/openengine/bullet/trace.cpp | 8 ++------ libs/openengine/bullet/trace.h | 14 +++++++++++--- 9 files changed, 40 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 1548cc1b0..2061b74d7 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index d312b6d54..07e5f0a3f 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -13,6 +12,14 @@ namespace ESM struct Pathgrid; } +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} + namespace Ogre { class Camera; diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 48632dba8..b2bdac683 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -2,6 +2,7 @@ #define _GAME_RENDER_OBJECTS_H #include +#include #include diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 082b561ef..1551f73b8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index c1f70f2ca..0b4ccd52f 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -1,12 +1,15 @@ #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H +#include + #include -#include "ptr.hpp" #include +#include "ptr.hpp" namespace MWWorld { + class World; class PhysicsSystem { diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index 8d98a482e..9cd76968a 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -7,8 +7,6 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include "pmove.h" - - //#include "bprintf.h" //#include "..\..\ESMParser\ESMParser\CELL.h" @@ -22,6 +20,8 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include +#include "trace.h" + //SceneInstance* global_lastscene = NULL; // Forward declaration: diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index fa303184e..29a050471 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -8,8 +8,6 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. #include #include -#include "trace.h" -#include "physic.hpp" #include @@ -18,6 +16,14 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. // Forwards-declare it! +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} + /*#ifndef COMPILING_PMOVE #include "Scene.h" extern SceneInstance* global_lastscene; diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 9f5398574..847059530 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -1,14 +1,10 @@ #include "trace.h" - - #include - - - - +#include "physic.hpp" +#include "pmove.h" void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 1bfe0c717..462d062eb 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -4,9 +4,17 @@ #include #include -#include -#include -#include "pmove.h" + +#include + + +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} enum traceWorldType From 8de2d24d0ef2094174ee0ad77b928519012a9ba9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 6 Feb 2013 21:57:59 -0800 Subject: [PATCH 568/916] Restore old ground check --- apps/openmw/mwworld/physicssystem.cpp | 5 +---- apps/openmw/mwworld/worldimp.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index c5c634d79..9262aa3c5 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -132,7 +132,6 @@ namespace MWWorld Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; - bool onground = false; if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); @@ -162,8 +161,7 @@ namespace MWWorld if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { @@ -190,7 +188,6 @@ namespace MWWorld verticalVelocity = clippedVelocity.z; physicActor->setVerticalForce(verticalVelocity - time*400.0f); - physicActor->setOnGround(onground); return newPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 085add7c9..6e063e1fe 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1369,10 +1369,12 @@ namespace MWWorld Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); RefData &refdata = mPlayer->getPlayer().getRefData(); - const OEngine::Physic::PhysicActor *physact = mPhysEngine->getCharacter(refdata.getHandle()); Ogre::Vector3 playerPos(refdata.getPosition().pos); - if(!physact->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) + std::pair hit = mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); + bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); + + if(!isOnGround || isUnderwater(*currentCell->mCell, playerPos)) return 2; if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) From 7d112e4d5c033b358638fb89255b4da9f5ed12fe Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 11:33:08 +0100 Subject: [PATCH 569/916] rewrote logic of content file loading --- apps/opencs/model/doc/document.cpp | 28 ++++++++++++++++++---------- apps/opencs/model/doc/document.hpp | 3 ++- apps/opencs/model/world/data.cpp | 5 +++++ apps/opencs/model/world/data.hpp | 5 +++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 14e34d0ba..796135c3f 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,15 +1,23 @@ #include "document.hpp" -#include +#include void CSMDoc::Document::load (const std::vector::const_iterator& begin, - const std::vector::const_iterator& end) + const std::vector::const_iterator& end, bool lastAsModified) { - for (std::vector::const_iterator iter (begin); iter!=end; ++iter) - std::cout << "pretending to load " << iter->string() << std::endl; + assert (begin!=end); - /// \todo load content files + std::vector::const_iterator end2 (end); + + if (lastAsModified) + --end2; + + for (std::vector::const_iterator iter (begin); iter!=end2; ++iter) + getData().loadFile (*iter, true); + + if (lastAsModified) + getData().loadFile (*end2, false); } void CSMDoc::Document::createBase() @@ -48,7 +56,7 @@ CSMDoc::Document::Document (const std::vector& files, b if (new_) --end; - load (files.begin(), end); + load (files.begin(), end, !new_); } if (new_ && files.size()==1) @@ -134,10 +142,10 @@ void CSMDoc::Document::saving() if (mSaveCount>15) { - mSaveCount = 0; - mSaveTimer.stop(); - mUndoStack.setClean(); - emit stateChanged (getState(), this); + mSaveCount = 0; + mSaveTimer.stop(); + mUndoStack.setClean(); + emit stateChanged (getState(), this); } } diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 28cc19d44..0162681bc 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -41,7 +41,8 @@ namespace CSMDoc Document& operator= (const Document&); void load (const std::vector::const_iterator& begin, - const std::vector::const_iterator& end); + const std::vector::const_iterator& end, bool lastAsModified); + ///< \param lastAsModified Store the last file in Modified instead of merging it into Base. void createBase(); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index a3522503e..5d4e63b27 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -59,4 +59,9 @@ QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) void CSMWorld::Data::merge() { mGlobals.merge(); +} + +void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) +{ + std::cout << "pretending to load " << path.string() << std::endl; } \ No newline at end of file diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index f7748cb5d..8a6cd736b 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include "idcollection.hpp" @@ -44,6 +46,9 @@ namespace CSMWorld void merge(); ///< Merge modified into base. + + void loadFile (const boost::filesystem::path& path, bool base); + ///< Merging content of a file into base or modified. }; } From adcaea464bda920b74ce9eea527eb4b004e41531 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 12:52:01 +0100 Subject: [PATCH 570/916] basic globals record loading --- apps/opencs/editor.cpp | 20 ++--------- apps/opencs/model/world/data.cpp | 24 ++++++++++++- apps/opencs/model/world/idcollection.cpp | 2 +- apps/opencs/model/world/idcollection.hpp | 45 ++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 22 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 02b494d3d..9161072f8 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -15,7 +15,7 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); - + connect (&mOpenDialog, SIGNAL(accepted()), this, SLOT(openFiles())); } @@ -50,23 +50,7 @@ void CS::Editor::openFiles() std::vector paths; mOpenDialog.getFileList(paths); CSMDoc::Document *document = mDocumentManager.addDocument(paths, false); - - static const char *sGlobals[] = - { - "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 - }; - - for (int i=0; sGlobals[i]; ++i) - { - ESM::Global record; - record.mId = sGlobals[i]; - record.mValue = i==0 ? 1 : 0; - record.mType = ESM::VT_Float; - document->getData().getGlobals().add (record); - } - - document->getData().merge(); /// \todo remove once proper ESX loading is implemented - + mViewManager.addView (document); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 5d4e63b27..9b89533a6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -5,6 +5,7 @@ #include +#include #include #include "idtable.hpp" @@ -63,5 +64,26 @@ void CSMWorld::Data::merge() void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) { - std::cout << "pretending to load " << path.string() << std::endl; + ESM::ESMReader reader; + /// \todo set encoder + reader.open (path.string()); + + // Note: We do not need to send update signals here, because at this point the model is not connected + // to any view. + while (reader.hasMoreRecs()) + { + ESM::NAME n = reader.getRecName(); + reader.getRecHeader(); + + switch (n.val) + { + case ESM::REC_GLOB: mGlobals.load (reader, base); break; + + + default: + + /// \todo throw an exception instead, once all records are implemented + reader.skipRecord(); + } + } } \ No newline at end of file diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp index fc4bb1ef6..5ea953279 100644 --- a/apps/opencs/model/world/idcollection.cpp +++ b/apps/opencs/model/world/idcollection.cpp @@ -3,4 +3,4 @@ CSMWorld::IdCollectionBase::IdCollectionBase() {} -CSMWorld::IdCollectionBase::~IdCollectionBase() {} \ No newline at end of file +CSMWorld::IdCollectionBase::~IdCollectionBase() {} diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 963997924..dd8fbcb38 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -11,9 +11,12 @@ #include -#include "columnbase.hpp" +#include + #include +#include "columnbase.hpp" + namespace CSMWorld { class IdCollectionBase @@ -67,9 +70,11 @@ namespace CSMWorld virtual std::string getId (const RecordBase& record) const = 0; ///< Return ID for \a record. /// - /// \attention Throw san exception, if the type of \a record does not match. + /// \attention Throws an exception, if the type of \a record does not match. virtual const RecordBase& getRecord (const std::string& id) const = 0; + + virtual void load (ESM::ESMReader& reader, bool base) = 0; }; ///< \brief Collection of ID-based records @@ -136,6 +141,8 @@ namespace CSMWorld virtual const RecordBase& getRecord (const std::string& id) const; + virtual void load (ESM::ESMReader& reader, bool base); + void addColumn (Column *column); }; @@ -309,6 +316,40 @@ namespace CSMWorld return (record2.isModified() ? record2.mModified : record2.mBase).mId; } + template + void IdCollection::load (ESM::ESMReader& reader, bool base) + { + std::string id = reader.getHNOString ("NAME"); + + /// \todo deal with deleted flag + + ESXRecordT record; + record.mId = id; + record.load (reader); + + int index = searchId (id); + + if (index==-1) + { + // new record + Record record2; + record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; + (base ? record2.mBase : record2.mModified) = record; + + appendRecord (record2); + } + else + { + // old record + Record& record2 = mRecords[index]; + + if (base) + record2.mBase = record; + else + record2.setModified (record); + } + } + template const RecordBase& IdCollection::getRecord (const std::string& id) const { From 21733e8181e11d23fc9358d6de2ca9fb61009d89 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 13:11:41 +0100 Subject: [PATCH 571/916] hide startup dialogue when opening open dialogue --- apps/opencs/editor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9161072f8..5cc659ff9 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -39,6 +39,7 @@ void CS::Editor::createDocument() void CS::Editor::loadDocument() { + mStartup.hide(); mOpenDialog.show(); mOpenDialog.raise(); mOpenDialog.activateWindow(); From c1cd8305bc9a01c2871aa097c6ad004dea8743c0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 13:13:06 +0100 Subject: [PATCH 572/916] a bit of cleanup for the previous commit --- apps/opencs/editor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 5cc659ff9..e2df365a2 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -47,7 +47,6 @@ void CS::Editor::loadDocument() void CS::Editor::openFiles() { - mStartup.hide(); std::vector paths; mOpenDialog.getFileList(paths); CSMDoc::Document *document = mDocumentManager.addDocument(paths, false); From dd2b7d5c63a050acf26a82399aecf9f967429b62 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Feb 2013 13:26:00 +0100 Subject: [PATCH 573/916] handle deleted records --- apps/opencs/model/world/idcollection.hpp | 56 +++++++++++++++++------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index dd8fbcb38..5a1d21ae4 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -321,32 +321,54 @@ namespace CSMWorld { std::string id = reader.getHNOString ("NAME"); - /// \todo deal with deleted flag - - ESXRecordT record; - record.mId = id; - record.load (reader); - int index = searchId (id); - if (index==-1) + if (reader.isNextSub ("DELE")) { - // new record - Record record2; - record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; - (base ? record2.mBase : record2.mModified) = record; + reader.skipRecord(); - appendRecord (record2); + if (index==-1) + { + // deleting a record that does not exist + + // ignore it for now + + /// \todo report the problem to the user + } + else if (base) + { + removeRows (index, 1); + } + else + { + mRecords[index].mState = RecordBase::State_Deleted; + } } else { - // old record - Record& record2 = mRecords[index]; + ESXRecordT record; + record.mId = id; + record.load (reader); - if (base) - record2.mBase = record; + if (index==-1) + { + // new record + Record record2; + record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; + (base ? record2.mBase : record2.mModified) = record; + + appendRecord (record2); + } else - record2.setModified (record); + { + // old record + Record& record2 = mRecords[index]; + + if (base) + record2.mBase = record; + else + record2.setModified (record); + } } } From 0d4b0bfd9396846971f112c948f8334fb89f9dc4 Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Thu, 7 Feb 2013 23:40:20 +0400 Subject: [PATCH 574/916] Trying to resolve sound issues on OS X with ffmpeg backend --- apps/openmw/CMakeLists.txt | 6 ++++++ apps/openmw/mwsound/ffmpeg_decoder.cpp | 1 + 2 files changed, 7 insertions(+) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e2cb0e5c4..b685c6083 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -125,6 +125,12 @@ if(APPLE) find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) target_link_libraries(openmw ${CARBON_FRAMEWORK} ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) + + if (FFMPEG_FOUND) + find_library(COREVIDEO_FRAMEWORK CoreVideo) + find_library(VDA_FRAMEWORK VideoDecodeAcceleration) + target_link_libraries(openmw ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK}) + endif() endif(APPLE) if(DPKG_PROGRAM) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 261a86ca6..00530a962 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -160,6 +160,7 @@ void FFmpeg_Decoder::open(const std::string &fname) { if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; mStream = &mFormatCtx->streams[j]; break; } From fe0e6c452d300cb288e5174b41ea498462d4ccc1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 12:11:10 -0800 Subject: [PATCH 575/916] Remove the unneeded playerMove object from PhysicsSystem --- apps/openmw/mwworld/physicssystem.cpp | 34 +++++++-------------------- apps/openmw/mwworld/physicssystem.hpp | 19 +++++++++++---- apps/openmw/mwworld/scene.cpp | 1 + apps/openmw/mwworld/scene.hpp | 4 ++-- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9262aa3c5..6c41d56e6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -9,8 +9,9 @@ #include #include -#include -#include +#include +#include +#include #include @@ -25,6 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; + static const float sStepSize = 9.0f; class MovementSolver { @@ -35,13 +37,13 @@ namespace MWWorld { traceResults trace; // no initialization needed - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,STEPSIZE), - position+Ogre::Vector3(0.0f,0.0f,STEPSIZE)+velocity*remainingTime, + newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), + position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0,0,STEPSIZE), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, verticalRotation, isInterior, engine); if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. @@ -197,20 +199,16 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : mRender(_rend), mEngine(0), mFreeFly (true) { - - playerphysics = new playerMove; // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); - playerphysics->mEngine = mEngine; } PhysicsSystem::~PhysicsSystem() { delete mEngine; - delete playerphysics; - } + OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() { return mEngine; @@ -279,15 +277,8 @@ namespace MWWorld void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) { - playerphysics->hasWater = hasWater; - if(hasWater){ - playerphysics->waterHeight = waterHeight; - } for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - { it->second->setCurrentWater(hasWater, waterHeight); - } - } btVector3 PhysicsSystem::getRayPoint(float extent) @@ -428,14 +419,8 @@ namespace MWWorld { // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow // start positions others than 0, 0, 0 - if (handle == "player") - { - playerphysics->ps.origin = position; - } - else - { + if (handle != "player") act->setPosition(position); - } } } @@ -474,7 +459,6 @@ namespace MWWorld bool PhysicsSystem::toggleCollisionMode() { - playerphysics->ps.move_type = (playerphysics->ps.move_type == PM_NOCLIP ? PM_NORMAL : PM_NOCLIP); for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { if (it->first=="player") diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 0b4ccd52f..cbdd9935e 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -1,15 +1,27 @@ #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H +#include + #include -#include -#include -#include "ptr.hpp" + +namespace OEngine +{ + namespace Render + { + class OgreRenderer; + } + namespace Physic + { + class PhysicEngine; + } +} namespace MWWorld { class World; + class Ptr; class PhysicsSystem { @@ -74,7 +86,6 @@ namespace MWWorld OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; bool mFreeFly; - playerMove* playerphysics; std::map handleToMesh; PhysicsSystem (const PhysicsSystem&); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 47751acb3..1966603fe 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -8,6 +8,7 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "physicssystem.hpp" #include "player.hpp" #include "localscripts.hpp" #include "esmstore.hpp" diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index ad6ad1559..2333a95ab 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -3,7 +3,7 @@ #include "../mwrender/renderingmanager.hpp" -#include "physicssystem.hpp" +#include "ptr.hpp" #include "globals.hpp" namespace Ogre @@ -34,9 +34,9 @@ namespace MWRender namespace MWWorld { + class PhysicsSystem; class Player; class CellStore; - class Ptr; class Scene { From ca6f8b6d88f8abf2f58386691eb3d0e86b3a3769 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 13:18:16 -0800 Subject: [PATCH 576/916] Reorganize a bit of code in the movement solver --- apps/openmw/mwworld/physicssystem.cpp | 70 ++++++++++++--------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 6c41d56e6..b6d507da9 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -27,6 +27,8 @@ namespace MWWorld static const float sMaxSlope = 60.0f; static const float sStepSize = 9.0f; + // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. + static const int sMaxIterations = 50; class MovementSolver { @@ -85,7 +87,7 @@ namespace MWWorld } public: - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, Ogre::Vector3 movement, float time, + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { const ESM::Position &refpos = ptr.getRefData().getPosition(); @@ -103,55 +105,44 @@ namespace MWWorld } traceResults trace; //no initialization needed - int iterations=0, maxIterations=50; //arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. - - if(!gravity) - { - movement = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * - movement; - } - else - { - movement = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * - movement; - } - - Ogre::Vector3 horizontalVelocity = movement/time; - float verticalVelocity = (gravity ? physicActor->getVerticalForce() : - horizontalVelocity.z); - Ogre::Vector3 velocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); // we need a copy of the velocity before we start clipping it for steps - Ogre::Vector3 clippedVelocity(horizontalVelocity.x, horizontalVelocity.y, verticalVelocity); - float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); - Ogre::Vector3 newPosition = position; + Ogre::Vector3 velocity; + if(!gravity) + { + velocity = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + movement / time; + } + else + { + velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * + movement / time; + velocity.z = physicActor->getVerticalForce(); + } + + // we need a copy of the velocity before we start clipping it for steps + Ogre::Vector3 clippedVelocity(velocity); if(gravity) { newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f) + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) { - if(getSlope(trace.planenormal) > sMaxSlope) - { - // if we're on a really steep slope, don't listen to user input - clippedVelocity.x = clippedVelocity.y = 0.0f; - } - else - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); - } + // if we're within 10 units of the ground, force velocity to track the ground + clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); } } + Ogre::Vector3 lastNormal(0.0f); + Ogre::Vector3 currentNormal(0.0f); + Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + Ogre::Vector3 newPosition = position; + int iterations = 0; do { // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); @@ -186,10 +177,9 @@ namespace MWWorld lastNormal = currentNormal; iterations++; - } while(iterations < maxIterations && remainingTime != 0.0f); + } while(iterations < sMaxIterations && remainingTime > 0.0f); - verticalVelocity = clippedVelocity.z; - physicActor->setVerticalForce(verticalVelocity - time*400.0f); + physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; } From cbdd459500cd2c164f633e11d2173d21e9ec4cb7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 15:48:41 -0800 Subject: [PATCH 577/916] Remove unneeded playerMove from PhysicActor --- apps/openmw/mwworld/physicssystem.cpp | 10 +--- libs/openengine/bullet/physic.cpp | 71 +-------------------------- libs/openengine/bullet/physic.hpp | 35 +------------ 3 files changed, 3 insertions(+), 113 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b6d507da9..cb8eb2a02 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -267,8 +267,7 @@ namespace MWWorld void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) { - for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) - it->second->setCurrentWater(hasWater, waterHeight); + // TODO: store and use } btVector3 PhysicsSystem::getRayPoint(float extent) @@ -405,13 +404,6 @@ namespace MWWorld mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); } } - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - if (handle != "player") - act->setPosition(position); - } } void PhysicsSystem::rotateObject (const Ptr& ptr) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 95313cdba..06f952305 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -34,14 +34,6 @@ namespace Physic Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map - pmove = new playerMove; - pmove->mEngine = mEngine; - btBoxShape* box = static_cast (mBody->getCollisionShape()); - if(box != NULL){ - btVector3 size = box->getHalfExtentsWithMargin(); - Ogre::Vector3 halfExtents = Ogre::Vector3(size.getX(), size.getY(), size.getZ()); - pmove->ps.halfExtents = halfExtents; - } } PhysicActor::~PhysicActor() @@ -50,38 +42,11 @@ namespace Physic mEngine->dynamicsWorld->removeRigidBody(mBody); delete mBody; } - delete pmove; - } - - void PhysicActor::setCurrentWater(bool hasWater, int waterHeight){ - pmove->hasWater = hasWater; - if(hasWater){ - pmove->waterHeight = waterHeight; - } - } - - void PhysicActor::setGravity(float gravity) - { - pmove->ps.gravity = gravity; - } - - void PhysicActor::setSpeed(float speed) - { - pmove->ps.speed = speed; } void PhysicActor::enableCollisions(bool collision) { collisionMode = collision; - if(collisionMode) - pmove->ps.move_type=PM_NORMAL; - else - pmove->ps.move_type=PM_NOCLIP; - } - - void PhysicActor::setJumpVelocity(float velocity) - { - pmove->ps.jump_velocity = velocity; } bool PhysicActor::getCollisionMode() @@ -89,23 +54,8 @@ namespace Physic return collisionMode; } - void PhysicActor::setMovement(signed char rightmove, signed char forwardmove, signed char upmove) - { - playerMove::playercmd& pm_ref = pmove->cmd; - pm_ref.rightmove = rightmove; - pm_ref.forwardmove = forwardmove; - pm_ref.upmove = upmove; - } - void PhysicActor::setPmoveViewAngles(float pitch, float yaw, float roll){ - pmove->ps.viewangles.x = pitch; - pmove->ps.viewangles.y = yaw; - pmove->ps.viewangles.z = roll; - } - - - - void PhysicActor::setRotation(const Ogre::Quaternion quat) + void PhysicActor::setRotation(const Ogre::Quaternion &quat) { if(!quat.equals(getRotation(), Ogre::Radian(0))){ mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); @@ -128,13 +78,6 @@ namespace Physic return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()); } - void PhysicActor::setPosition(const Ogre::Vector3 pos) - { - mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); - btVector3 vec = mBody->getWorldTransform().getOrigin(); - pmove->ps.origin = Ogre::Vector3(vec.getX(), vec.getY(), vec.getZ()); - } - void PhysicActor::setScale(float scale){ Ogre::Vector3 position = getPosition(); Ogre::Quaternion rotation = getRotation(); @@ -148,12 +91,6 @@ namespace Physic //Create the newly scaled rigid body mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation); mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map - btBoxShape* box = static_cast (mBody->getCollisionShape()); - if(box != NULL){ - btVector3 size = box->getHalfExtentsWithMargin(); - Ogre::Vector3 halfExtents = Ogre::Vector3(size.getX(), size.getY(), size.getZ()); - pmove->ps.halfExtents = halfExtents; - } } Ogre::Vector3 PhysicActor::getHalfExtents() const @@ -190,12 +127,6 @@ namespace Physic return collisionMode && onGround; } - void PhysicActor::runPmove(){ - Pmove(pmove); - Ogre::Vector3 newpos = pmove->ps.origin; - mBody->getWorldTransform().setOrigin(btVector3(newpos.x, newpos.y, newpos.z)); - } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 4bc926b8a..aa832ddcc 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -18,7 +18,6 @@ class btSequentialImpulseConstraintSolver; class btCollisionDispatcher; class btDiscreteDynamicsWorld; class btHeightfieldTerrainShape; -struct playerMove; namespace BtOgre { @@ -65,25 +64,12 @@ namespace Physic ~PhysicActor(); - void setCurrentWater(bool hasWater, int waterHeight); - - /** - * This function sets the movement keys for pmove - */ - void setMovement(signed char rightmove, signed char forwardmove, signed char upmove); - /** * This adjusts the rotation of a PhysicActor * If we have any problems with this (getting stuck in pmove) we should change it * from setting the visual orientation to setting the orientation of the rigid body directly. */ - void setRotation(const Ogre::Quaternion quat); - - void setGravity(float gravity); - - void setSpeed(float speed); - - void setJumpVelocity(float velocity); + void setRotation(const Ogre::Quaternion &quat); void enableCollisions(bool collision); @@ -100,18 +86,6 @@ namespace Physic */ Ogre::Quaternion getRotation(); - /** - * Sets the position of mBody from a visual position input. - * For most cases this should not be used. We should instead let pmove move the PhysicActor around for us - */ - void setPosition(const Ogre::Vector3 pos); - - /** - * Sets the view angles for pmove directly. - * Remember, add 90 for yaw. Set roll to 0. - */ - void setPmoveViewAngles(float pitch, float yaw, float roll); - /** * Sets the scale of the PhysicActor */ @@ -136,11 +110,6 @@ namespace Physic bool getOnGround() const; - /** - * Runs pmove for this PhysicActor - */ - void runPmove(); - //HACK: in Visual Studio 2010 and presumably above, this structures alignment // must be 16, but the built in operator new & delete don't properly // perform this alignment. @@ -161,8 +130,6 @@ namespace Physic std::string mMesh; PhysicEngine* mEngine; std::string mName; - playerMove* pmove; - }; /** From d47d2216f2c9494d6a1b4e48df658485ea568bdb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 16:18:29 -0800 Subject: [PATCH 578/916] Use some const references where appropriate --- apps/openmw/mwworld/physicssystem.cpp | 6 ++-- libs/openengine/bullet/physic.cpp | 42 +++++++++++++++------------ libs/openengine/bullet/physic.hpp | 27 ++++++++--------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index cb8eb2a02..8bf852f42 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -409,8 +409,8 @@ namespace MWWorld void PhysicsSystem::rotateObject (const Ptr& ptr) { Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); - Ogre::Quaternion rotation = node->getOrientation(); + const std::string &handle = node->getName(); + const Ogre::Quaternion &rotation = node->getOrientation(); if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { //Needs to be changed @@ -428,7 +428,7 @@ namespace MWWorld void PhysicsSystem::scaleObject (const Ptr& ptr) { Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); + const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { removeObject(handle); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 06f952305..2b26c3a48 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -27,8 +27,9 @@ namespace Physic COL_RAYCASTING = BIT(3) }; - PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): - mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) + : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) + , mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) { mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); @@ -38,7 +39,8 @@ namespace Physic PhysicActor::~PhysicActor() { - if(mBody){ + if(mBody) + { mEngine->dynamicsWorld->removeRigidBody(mBody); delete mBody; } @@ -321,18 +323,21 @@ namespace Physic mHeightFieldMap.erase(name); } - void PhysicEngine::adjustRigidBody(RigidBody* body, Ogre::Vector3 position, Ogre::Quaternion rotation, - Ogre::Vector3 scaledBoxTranslation, Ogre::Quaternion boxRotation){ + void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + const Ogre::Vector3 &scaledBoxTranslation, const Ogre::Quaternion &boxRotation) + { btTransform tr; - rotation = rotation * boxRotation; - Ogre::Vector3 transrot = rotation * scaledBoxTranslation; + Ogre::Quaternion boxrot = rotation * boxRotation; + Ogre::Vector3 transrot = boxrot * scaledBoxTranslation; Ogre::Vector3 newPosition = transrot + position; - + tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z)); - tr.setRotation(btQuaternion(rotation.x,rotation.y,rotation.z,rotation.w)); + tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w)); body->setWorldTransform(tr); } - void PhysicEngine::boxAdjustExternal(std::string mesh, RigidBody* body, float scale, Ogre::Vector3 position, Ogre::Quaternion rotation){ + void PhysicEngine::boxAdjustExternal(const std::string &mesh, RigidBody* body, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) + { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; //std::cout << "The string" << outputstring << "\n"; @@ -345,7 +350,8 @@ namespace Physic adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); } - RigidBody* PhysicEngine::createAndAdjustRigidBody(std::string mesh,std::string name,float scale, Ogre::Vector3 position, Ogre::Quaternion rotation, + RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation) { std::string sid = (boost::format("%07.3f") % scale).str(); @@ -406,7 +412,7 @@ namespace Physic } } - void PhysicEngine::removeRigidBody(std::string name) + void PhysicEngine::removeRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -426,7 +432,7 @@ namespace Physic } } - void PhysicEngine::deleteRigidBody(std::string name) + void PhysicEngine::deleteRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -446,7 +452,7 @@ namespace Physic } } - RigidBody* PhysicEngine::getRigidBody(std::string name) + RigidBody* PhysicEngine::getRigidBody(const std::string &name) { RigidBodyContainer::iterator it = ObjectMap.find(name); if (it != ObjectMap.end() ) @@ -469,8 +475,8 @@ namespace Physic } } - void PhysicEngine::addCharacter(std::string name, std::string mesh, - Ogre::Vector3 position, float scale, Ogre::Quaternion rotation) + void PhysicEngine::addCharacter(const std::string &name, const std::string &mesh, + const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation) { // Remove character with given name, so we don't make memory // leak when character would be added twice @@ -483,7 +489,7 @@ namespace Physic PhysicActorMap[name] = newActor; } - void PhysicEngine::removeCharacter(std::string name) + void PhysicEngine::removeCharacter(const std::string &name) { //std::cout << "remove"; PhysicActorContainer::iterator it = PhysicActorMap.find(name); @@ -499,7 +505,7 @@ namespace Physic } } - PhysicActor* PhysicEngine::getCharacter(std::string name) + PhysicActor* PhysicEngine::getCharacter(const std::string &name) { PhysicActorContainer::iterator it = PhysicActorMap.find(name); if (it != PhysicActorMap.end() ) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index aa832ddcc..1a28023a9 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -60,7 +60,7 @@ namespace Physic class PhysicActor { public: - PhysicActor(std::string name, std::string mesh, PhysicEngine *engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale); + PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale); ~PhysicActor(); @@ -178,19 +178,21 @@ namespace Physic * Creates a RigidBody. It does not add it to the simulation. * After created, the body is set to the correct rotation, position, and scale */ - RigidBody* createAndAdjustRigidBody(std::string mesh,std::string name,float scale, Ogre::Vector3 position, Ogre::Quaternion rotation, + RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0); /** * Adjusts a rigid body to the right position and rotation */ - void adjustRigidBody(RigidBody* body, Ogre::Vector3 position, Ogre::Quaternion rotation, - Ogre::Vector3 scaledBoxTranslation = Ogre::Vector3::ZERO, Ogre::Quaternion boxRotation = Ogre::Quaternion::IDENTITY); + void adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + const Ogre::Vector3 &scaledBoxTranslation = Ogre::Vector3::ZERO, + const Ogre::Quaternion &boxRotation = Ogre::Quaternion::IDENTITY); /** Mainly used to (but not limited to) adjust rigid bodies based on box shapes to the right position and rotation. */ - void boxAdjustExternal(std::string mesh, RigidBody* body, float scale, Ogre::Vector3 position, Ogre::Quaternion rotation); + void boxAdjustExternal(const std::string &mesh, RigidBody* body, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); /** * Add a HeightField to the simulation */ @@ -211,35 +213,35 @@ namespace Physic /** * Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap. */ - void removeRigidBody(std::string name); + void removeRigidBody(const std::string &name); /** * Delete a RigidBody, and remove it from RigidBodyMap. */ - void deleteRigidBody(std::string name); + void deleteRigidBody(const std::string &name); /** * Return a pointer to a given rigid body. * TODO:check if exist */ - RigidBody* getRigidBody(std::string name); + RigidBody* getRigidBody(const std::string &name); /** * Create and add a character to the scene, and add it to the ActorMap. */ - void addCharacter(std::string name, std::string mesh, - Ogre::Vector3 position, float scale, Ogre::Quaternion rotation); + void addCharacter(const std::string &name, const std::string &mesh, + const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation); /** * Remove a character from the scene. TODO:delete it! for now, a small memory leak^^ done? */ - void removeCharacter(std::string name); + void removeCharacter(const std::string &name); /** * Return a pointer to a character * TODO:check if the actor exist... */ - PhysicActor* getCharacter(std::string name); + PhysicActor* getCharacter(const std::string &name); /** * This step the simulation of a given time. @@ -307,7 +309,6 @@ namespace Physic BtOgre::DebugDrawer* mDebugDrawer; bool isDebugCreated; bool mDebugActive; - }; From f5afa43db5037f4e8f4343db6ef933c7bb7279a7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 7 Feb 2013 17:45:41 -0800 Subject: [PATCH 579/916] Remove an unneeded parameter --- apps/openmw/mwworld/physicssystem.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 8bf852f42..a5dd7f369 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -56,20 +56,17 @@ namespace MWWorld return false; } - static void clipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, - const float overbounce) + static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce) { //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. - float backoff; - - backoff = in.dotProduct(normal); + float backoff = inout.dotProduct(normal); if(backoff < 0.0f) backoff *= overbounce; else backoff /= overbounce; - out = in - (normal*backoff); + inout -= normal*backoff; } static void projectVelocity(Ogre::Vector3& velocity, const Ogre::Vector3& direction) @@ -134,7 +131,7 @@ namespace MWWorld if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) { // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, clippedVelocity, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } } @@ -171,7 +168,7 @@ namespace MWWorld // std::cout<< "stepped" < Date: Fri, 8 Feb 2013 09:58:19 +0100 Subject: [PATCH 580/916] basic gmst support --- apps/opencs/model/world/data.cpp | 7 +++++++ apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 6 +++--- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 3 +++ components/esm/loadgmst.cpp | 23 ++++++++++++++++++++++- components/esm/loadgmst.hpp | 11 ++++++++--- 9 files changed, 58 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 9b89533a6..89c19f032 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -28,7 +28,13 @@ CSMWorld::Data::Data() mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); mGlobals.addColumn (new FloatValueColumn); + mGmsts.addColumn (new StringIdColumn); + mGmsts.addColumn (new RecordStateColumn); + mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); + ///< \todo add type and value + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); + addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); } CSMWorld::Data::~Data() @@ -78,6 +84,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) switch (n.val) { case ESM::REC_GLOB: mGlobals.load (reader, base); break; + case ESM::REC_GMST: mGmsts.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8a6cd736b..519817a3b 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -18,6 +19,7 @@ namespace CSMWorld class Data { IdCollection mGlobals; + IdCollection mGmsts; std::vector mModels; std::map mModelIndex; diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index d8775643a..c006852bc 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -18,6 +18,7 @@ namespace { { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -25,6 +26,7 @@ namespace static const TypeData sIdArg[] = { { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 4a73feb12..9ff7d17b1 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -33,12 +33,12 @@ namespace CSMWorld enum Type { Type_None, - Type_Globals, - Type_Global, + Type_VerificationResults, + Type_Gmsts, + Type_Gmst - Type_VerificationResults }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index f5cc3d85b..4fd03041f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -71,6 +71,10 @@ void CSVDoc::View::setupWorldMenu() connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView())); world->addAction (globals); + QAction *gmsts = new QAction (tr ("Game settings"), this); + connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView())); + world->addAction (gmsts); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -217,4 +221,9 @@ void CSVDoc::View::verify() void CSVDoc::View::addGlobalsSubView() { addSubView (CSMWorld::UniversalId::Type_Globals); +} + +void CSVDoc::View::addGmstsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Gmsts); } \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 05d7210dc..6bdd54e6b 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -99,6 +99,8 @@ namespace CSVDoc void verify(); void addGlobalsSubView(); + + void addGmstsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 080a175ea..351007ded 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -11,6 +11,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Globals, new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Gmsts, + new CSVDoc::SubViewFactoryWithCreateFlag (false)); + manager.add (CSMWorld::UniversalId::Type_Global, new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index a73095a66..e9852ec07 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -76,8 +76,29 @@ std::string GameSetting::getString() const { if (mType==VT_String) return mStr; - + throw std::runtime_error ("GMST " + mId + " is not a string"); } + void GameSetting::blank() + { + mStr.clear(); + mI = 0; + mF = 0; + mType = VT_Float; + } + + bool operator== (const GameSetting& left, const GameSetting& right) + { + if (left.mType!=right.mType) + return false; + + switch (left.mType) + { + case VT_Float: return left.mF==right.mF; + case VT_Int: return left.mI==right.mI; + case VT_String: return left.mStr==right.mStr; + default: return false; + } + } } diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index ab9a9551e..f7aec5c76 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -26,17 +26,22 @@ struct GameSetting VarType mType; void load(ESMReader &esm); - + int getInt() const; ///< Throws an exception if GMST is not of type int or float. - + float getFloat() const; ///< Throws an exception if GMST is not of type int or float. - + std::string getString() const; ///< Throwns an exception if GMST is not of type string. void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID). }; + + bool operator== (const GameSetting& left, const GameSetting& right); } #endif From cce2d63433a137fa47856670bc433291e4321852 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 8 Feb 2013 12:20:03 +0100 Subject: [PATCH 581/916] added type column to gmst table --- apps/opencs/model/world/columns.hpp | 23 +++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1e2de9265..747387676 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -91,6 +91,29 @@ namespace CSMWorld return false; } }; + + template + struct VarTypeColumn : public Column + { + VarTypeColumn() : Column ("Type", ColumnBase::Display_Float) {} + + virtual QVariant get (const Record& record) const + { + return static_cast (record.get().mType); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT base = record.getBase(); + base.mType = static_cast (data.toInt()); + record.setModified (base); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 89c19f032..69e62db01 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -31,7 +31,8 @@ CSMWorld::Data::Data() mGmsts.addColumn (new StringIdColumn); mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); - ///< \todo add type and value + mGmsts.addColumn (new VarTypeColumn); + ///< \todo add value addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 828695f295e07cd9ece9cbc6333a83c49cf033b3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 8 Feb 2013 14:48:38 +0100 Subject: [PATCH 582/916] added value column to gmst table --- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 41 +++++++++++++++++++++- apps/opencs/model/world/data.cpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 4 +++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 38b73ee3f..f1871a6a9 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -28,7 +28,8 @@ namespace CSMWorld { Display_String, Display_Integer, - Display_Float + Display_Float, + Display_Var }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 747387676..fb94cbf59 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -95,7 +95,7 @@ namespace CSMWorld template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_Float) {} + VarTypeColumn() : Column ("Type", ColumnBase::Display_Integer) {} virtual QVariant get (const Record& record) const { @@ -114,6 +114,45 @@ namespace CSMWorld return true; } }; + + template + struct VarValueColumn : public Column + { + VarValueColumn() : Column ("Value", ColumnBase::Display_Var) {} + + virtual QVariant get (const Record& record) const + { + switch (record.get().mType) + { + case ESM::VT_String: return record.get().mStr.c_str(); break; + case ESM::VT_Int: return record.get().mI; break; + case ESM::VT_Float: return record.get().mF; break; + + default: return QVariant(); + } + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT base = record.getBase(); + + switch (record.get().mType) + { + case ESM::VT_String: base.mStr = data.toString().toUtf8().constData(); break; + case ESM::VT_Int: base.mI = data.toInt(); break; + case ESM::VT_Float: base.mF = data.toFloat(); break; + + default: break; + } + + record.setModified (base); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 69e62db01..f120c75f1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -32,7 +32,7 @@ CSMWorld::Data::Data() mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); mGmsts.addColumn (new VarTypeColumn); - ///< \todo add value + mGmsts.addColumn (new VarValueColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 2bf6577b1..e16de99ef 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -64,6 +64,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM /// \todo configure widget properly (range, format?) layout->addWidget (widget = new QDoubleSpinBox, i, 1); break; + + default: break; // silence warnings for other times for now } } else @@ -76,6 +78,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM layout->addWidget (widget = new QLabel, i, 1); break; + + default: break; // silence warnings for other times for now } } From 735c1ec2ae658a490d7bf5a3035bdde28ad19cb6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 8 Feb 2013 13:12:34 -0800 Subject: [PATCH 583/916] Cleanup trace.cpp/h --- libs/openengine/bullet/trace.cpp | 256 +++++++++++-------------------- libs/openengine/bullet/trace.h | 51 +----- 2 files changed, 99 insertions(+), 208 deletions(-) diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 847059530..138411e11 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -3,190 +3,116 @@ #include +#include +#include + #include "physic.hpp" #include "pmove.h" -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object +enum traceWorldType { - //static float lastyaw = 0.0f; - //static float lastpitch = 0.0f; - //if (!traceobj) - // return; - - //if (!traceobj->incellptr) - // return; - - - const Ogre::Vector3 rayDir = end - start; - - - - - - - - NewPhysTraceResults out; - //std::cout << "Starting trace\n"; - //Ogre::Vector3 startReplace = Ogre::Vector3(650,950, 45); - //Ogre::Vector3 endReplace = startReplace; - //endReplace.z -= .25; - - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), isInterior, enginePass); - - if (out.fraction < 0.001f) - results->startsolid = true; - else - results->startsolid = false; - - - //results->allsolid = out.startSolid; - - // If outside and underground, we're solid - /*if (isInterior) - { - const Ogre::Vector3 height = GetGroundPosition(start, CellCoords(traceCell->data->gridX, traceCell->data->gridY) ); - if (start.yPos - height.yPos < (-2.0f * BBHalfExtents.yPos) ) - { - results->allsolid = true; - } - else - results->allsolid = false; - }*/ - - // If inside and out of the tree, we're solid - //else - //{ - results->allsolid = out.startSolid; - //std::cout << "allsolid" << results->allsolid << "\n"; - //} - - if (!hasHit) - { - results->endpos = end; - results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - results->entityNum = ENTITYNUM_NONE; - results->fraction = 1.0f; - } - else - { - results->fraction = out.fraction; - results->planenormal = out.hitNormal; - results->endpos = rayDir * results->fraction + start; - results->entityNum = ENTITYNUM_WORLD; - /*bprintf("Start: (%f, %f, %f) End: (%f, %f, %f) TraceDir: (%f, %f, %f) HitNormal: (%f, %f, %f) Fraction: %f Hitpos: (%f, %f, %f) CompensatedHitpos: (%f, %f, %f)\n", - start.xPos, start.yPos, start.zPos, - end.xPos, end.yPos, end.zPos, - rayDir.xPos, rayDir.yPos, rayDir.zPos, - results->planenormal.xPos, results->planenormal.yPos, results->planenormal.zPos, results->fraction, - out.endPos.xPos, out.endPos.yPos, out.endPos.zPos, - results->endpos.xPos, results->endpos.yPos, results->endpos.zPos);*/ - } -} + collisionWorldTrace = 1, + pickWorldTrace = 2, + bothWorldTrace = collisionWorldTrace | pickWorldTrace +}; +enum collaborativePhysicsType +{ + No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass) + Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics) + Only_Pickup = 2, // This object only has pickup physics but no collision physics (example: items dropped on the ground) + Both_Physics = 3 // This object has both kinds of physics (example: activators) +}; +struct NewPhysTraceResults +{ + Ogre::Vector3 endPos; + Ogre::Vector3 hitNormal; + float fraction; + bool startSolid; + //const Object* hitObj; +}; template -const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) +static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, + const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, + OEngine::Physic::PhysicEngine* enginePass) { - //if (!traceobj->incellptr) - // return false; - //if(enginePass->dynamicsWorld->getCollisionObjectArray().at(60)->getCollisionShape()->isConvex()) - // std::cout << "It's convex\n"; - - - - const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); - const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); - const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z + const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); + const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); + const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); - //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); - const btTransform from(btrot, btstart); - const btTransform to(btrot, btend); + //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); + const btTransform from(btrot, btstart); + const btTransform to(btrot, btend); - // warning: unused variable ... - /* - float x = from.getOrigin().getX(); - float y = from.getOrigin().getY(); - float z = from.getOrigin().getZ(); - float x2 = to.getOrigin().getX(); - float y2 = to.getOrigin().getY(); - float z2 = to.getOrigin().getZ(); - */ - - //std::cout << "BtFrom: " << x << "," << y << "," << z << "\n"; - //std::cout << "BtTo: " << x2 << "," << y2 << "," << z2 << "\n"; - //std::cout << "BtTo: " << to.getOrigin().getX() << "," << to.getOrigin().getY() << "," << to.getOrigin().getZ() << "\n"; + btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); + newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; - btCollisionWorld::ClosestConvexResultCallback - newTraceCallback(btstart, btend); + enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); - newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; - - - enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); - //newTraceCallback. - - - //std::cout << "NUM: " << enginePass->dynamicsWorld->getNumCollisionObjects() << "\n"; + // Copy the hit data over to our trace results struct: + out->fraction = newTraceCallback.m_closestHitFraction; - // Copy the hit data over to our trace results struct: - out->fraction = newTraceCallback.m_closestHitFraction; + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + out->hitNormal.x = tracehitnormal.x(); + out->hitNormal.y = tracehitnormal.y(); + out->hitNormal.z = tracehitnormal.z(); - Ogre::Vector3& outhitnormal = out->hitNormal; - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; + out->endPos.x = tracehitpos.x(); + out->endPos.y = tracehitpos.y(); + out->endPos.z = tracehitpos.z(); - outhitnormal.x = tracehitnormal.x(); - outhitnormal.y = tracehitnormal.y(); - outhitnormal.z = tracehitnormal.z(); - - Ogre::Vector3& outhitpos = out->endPos; - const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; - - outhitpos.x = tracehitpos.x(); - outhitpos.y = tracehitpos.y(); - outhitpos.z= tracehitpos.z(); - - // StartSolid test: - { - out->startSolid = false; - //btCollisionObject collision; - //collision.setCollisionShape(const_cast(&newshape) ); - - //CustomContactCallback crb; - - //world.world->contactTest(&collision, crb); - //out->startSolid = crb.hit; - - // If outside and underground, we're solid - if (!isInterior) //Check if we are interior - { - } - - // If inside and out of the tree, we're solid - else - { - btVector3 aabbMin, aabbMax; - enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); - //std::cout << "AABBMIN" << aabbMin.getX() <<"," <startSolid = false; + if(isInterior) + { + // If inside and out of the tree, we're solid + btVector3 aabbMin, aabbMax; + enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); + btVector3 point(start.x, start.y, start.z); + if(!TestPointAgainstAabb2(aabbMin, aabbMax, point)) + { + //We're solid + //THIS NEEDS TO BE TURNED OFF IF WE WANT FALLING IN EXTERIORS TO WORK CORRECTLY!!!!!!! //out->startSolid = true; - } - } - } + } + } + } - const bool hasHit = newTraceCallback.hasHit(); - - - - - return hasHit; + return newTraceCallback.hasHit(); +} + + +void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object +{ + NewPhysTraceResults out; + const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, + Ogre::Vector3(0.0f, 0.0f, 0.0f), + isInterior, enginePass); + if (out.fraction < 0.001f) + results->startsolid = true; + else + results->startsolid = false; + results->allsolid = out.startSolid; + + if(!hasHit) + { + results->endpos = end; + results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); + results->entityNum = ENTITYNUM_NONE; + results->fraction = 1.0f; + } + else + { + results->fraction = out.fraction; + results->planenormal = out.hitNormal; + results->endpos = (end-start)*results->fraction + start; + results->entityNum = ENTITYNUM_WORLD; + } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 462d062eb..94708d403 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -1,10 +1,6 @@ #ifndef OENGINE_BULLET_TRACE_H #define OENGINE_BULLET_TRACE_H - -#include -#include - #include @@ -17,52 +13,21 @@ namespace OEngine } -enum traceWorldType -{ - collisionWorldTrace = 1, - pickWorldTrace = 2, - bothWorldTrace = collisionWorldTrace | pickWorldTrace -}; - -enum collaborativePhysicsType -{ - No_Physics = 0, // Both are empty (example: statics you can walk through, like tall grass) - Only_Collision = 1, // This object only has collision physics but no pickup physics (example: statics) - Only_Pickup = 2, // This object only has pickup physics but no collision physics (example: items dropped on the ground) - Both_Physics = 3 // This object has both kinds of physics (example: activators) -}; - -struct NewPhysTraceResults -{ - Ogre::Vector3 endPos; - Ogre::Vector3 hitNormal; - float fraction; - bool startSolid; - //const Object* hitObj; -}; struct traceResults { - Ogre::Vector3 endpos; - Ogre::Vector3 planenormal; + Ogre::Vector3 endpos; + Ogre::Vector3 planenormal; - float fraction; + float fraction; - int surfaceFlags; - int contents; - int entityNum; + int surfaceFlags; + int contents; + int entityNum; - bool allsolid; - bool startsolid; + bool allsolid; + bool startsolid; }; - - -template -const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -//template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); -//template const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const Ogre::Vector3& rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); - void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); - #endif From eefbdde6de862e15f27ae90c410687eb8a988729 Mon Sep 17 00:00:00 2001 From: Mark Siewert Date: Sat, 9 Feb 2013 13:00:57 +0100 Subject: [PATCH 584/916] - For pull request: remove all instances of maps used to track refnumbers. - new file: apps/openmw/mwworld/store.cpp, had to move reference merging method out of the header file to prevent three-way recursion/unresolved forward references in custom compare operators. --- apps/openmw/main.cpp | 6 +- apps/openmw/mwworld/cells.cpp | 12 ++-- apps/openmw/mwworld/cellstore.cpp | 42 ++++++++++++- apps/openmw/mwworld/cellstore.hpp | 84 ++++---------------------- apps/openmw/mwworld/containerstore.cpp | 28 ++++----- apps/openmw/mwworld/containerstore.hpp | 72 +++++++++++----------- apps/openmw/mwworld/localscripts.cpp | 6 +- apps/openmw/mwworld/scene.cpp | 6 +- apps/openmw/mwworld/store.cpp | 65 ++++++++++++++++++++ apps/openmw/mwworld/store.hpp | 64 +++----------------- apps/openmw/mwworld/worldimp.cpp | 14 ++--- components/esm/loadcell.cpp | 26 +++++--- components/esm/loadcell.hpp | 33 +++++----- 13 files changed, 233 insertions(+), 225 deletions(-) create mode 100644 apps/openmw/mwworld/store.cpp diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 1be669ae0..86978c9b1 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -213,8 +213,10 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat StringsVector plugin = variables["plugin"].as(); // Removed check for 255 files, which would be the hard-coded limit in Morrowind. - // I'll keep the following variable in, maybe we can use it for somethng different. - int cnt = master.size() + plugin.size(); + // I'll keep the following variable in, maybe we can use it for something different. + // Say, a feedback like "loading file x/cnt". + // Commenting this out for now to silence compiler warning. + //int cnt = master.size() + plugin.size(); // Prepare loading master/plugin files (i.e. send filenames to engine) for (std::vector::size_type i = 0; i < master.size(); i++) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 7e421dc55..59c62e37d 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -42,30 +42,30 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) cellStore.mContainers.mList.begin()); iter!=cellStore.mContainers.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.mCreatures.mList.begin()); iter!=cellStore.mCreatures.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } for (CellRefList::List::iterator iter ( cellStore.mNpcs.mList.begin()); iter!=cellStore.mNpcs.mList.end(); ++iter) { - Ptr container (&iter->second, &cellStore); + Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->second.mBase->mInventory, mStore); + iter->mBase->mInventory, mStore); } } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 7f1cdc469..baf4fea32 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -10,6 +10,41 @@ namespace MWWorld { + + template + void CellRefList::load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) + { + // Get existing reference, in case we need to overwrite it. + typename std::list::iterator iter = std::find(mList.begin(), mList.end(), ref.mRefnum); + + // Skip this when reference was deleted. + // TODO: Support respawning references, in this case, we need to track it somehow. + if (ref.mDeleted) { + mList.erase(iter); + return; + } + + // for throwing exception on unhandled record type + const MWWorld::Store &store = esmStore.get(); + const X *ptr = store.search(ref.mRefID); + + /// \note no longer redundant - changed to Store::search(), don't throw + /// an exception on miss, try to continue (that's how MW does it, anyway) + if (ptr == NULL) { + std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl; + } else { + if (iter != mList.end()) + *iter = LiveRef(ref, ptr); + else + mList.push_back(LiveRef(ref, ptr)); + } + } + + template bool operator==(const LiveCellRef& ref, int pRefnum) + { + return (ref.mRef.mRefnum == pRefnum); + } + CellStore::CellStore (const ESM::Cell *cell) : mCell (cell), mState (State_Unloaded) { @@ -95,7 +130,8 @@ namespace MWWorld { // Don't load reference if it was moved to a different cell. std::string lowerCase = Misc::StringUtils::lowerCase(ref.mRefID); - if (mCell->mMovedRefs.find(ref.mRefnum) != mCell->mMovedRefs.end()) { + ESM::MovedCellRefTracker::const_iterator iter = std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefnum); + if (iter != mCell->mMovedRefs.end()) { continue; } int rec = store.find(ref.mRefID); @@ -141,8 +177,8 @@ namespace MWWorld for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); it++) { // Doesn't seem to work in one line... huh? Too sleepy to check... - //const ESM::CellRef &ref0 = it->second; - ESM::CellRef &ref = const_cast(it->second); + ESM::CellRef &ref = const_cast(*it); + //ESM::CellRef &ref = const_cast(it->second); std::string lowerCase; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index cbaf56458..c182f196b 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,11 +9,12 @@ #include "refdata.hpp" #include "esmstore.hpp" +struct C; namespace MWWorld { class Ptr; class ESMStore; - + /// A reference to one object (of any type) in a cell. /// /// Constructing this with a CellRef instance in the constructor means that @@ -42,88 +43,25 @@ namespace MWWorld /// runtime-data RefData mData; }; + + template bool operator==(const LiveCellRef& ref, int pRefnum); /// A list of cell references template struct CellRefList { typedef LiveCellRef LiveRef; - typedef std::map List; + typedef std::list List; List mList; // Search for the given reference in the given reclist from // ESMStore. Insert the reference into the list if a match is // found. If not, throw an exception. - /// Searches for reference of appropriate type in given ESMStore. - /// If reference exists, loads it into container, throws an exception - /// on miss - void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) - { - // Skip this when reference was deleted. - // TODO: Support respawning references, in this case, we need to track it somehow. - if (ref.mDeleted) { - mList.erase(ref.mRefnum); - return; - } - - // for throwing exception on unhandled record type - const MWWorld::Store &store = esmStore.get(); - const X *ptr = store.search(ref.mRefID); - - /// \note no longer redundant - changed to Store::search(), don't throw - /// an exception on miss, try to continue (that's how MW does it, anyway) - if (ptr == NULL) { - std::cout << "Warning: could not resolve cell reference " << ref.mRefID << ", trying to continue anyway" << std::endl; - } else - mList[ref.mRefnum] = LiveRef(ref, ptr); - } - - LiveRef *find (const std::string& name) - { - for (typename std::map::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - { - if (iter->second.mData.getCount() > 0 && iter->second.mRef.mRefID == name) - return &iter->second; - } - - return 0; - } - - LiveRef &insert(const LiveRef &item) { - mList[item.mRef.mRefnum] = item; - return mList[item.mRef.mRefnum]; - } - }; - - /// A list of container references. These references do not track their mRefnumber. - /// Otherwise, taking 1 of 20 instances of an object would produce multiple objects - /// with the same reference. - /// Unfortunately, this also means that we need a different STL container. - /// (cells use CellRefList, where refs can be located according to their refnumner, - /// which uses a map; container items do not make use of the refnumber, so we - /// can't use a map with refnumber keys.) - template - struct ContainerRefList - { - typedef LiveCellRef LiveRef; - typedef std::list List; - List mList; - - /// Searches for reference of appropriate type in given ESMStore. - /// If reference exists, loads it into container, throws an exception - /// on miss - void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore) - { - // for throwing exception on unhandled record type - const MWWorld::Store &store = esmStore.get(); - const X *ptr = store.find(ref.mRefID); - - /// \note redundant because Store::find() throws exception on miss - if (ptr == NULL) { - throw std::runtime_error("Error resolving cell reference " + ref.mRefID); - } - mList.push_back(LiveRef(ref, ptr)); - } + // Moved to cpp file, as we require a custom compare operator for it, + // and the build will fail with an ugly three-way cyclic header dependence + // so we need to pass the instantiation of the method to the lnker, when + // all methods are known. + void load(ESM::CellRef &ref, const MWWorld::ESMStore &esmStore); LiveRef *find (const std::string& name) { @@ -236,7 +174,7 @@ namespace MWWorld { for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) - if (!functor (iter->second.mRef, iter->second.mData)) + if (!functor (iter->mRef, iter->mData)) return false; return true; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 36addee86..bca4073b5 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -21,11 +21,11 @@ namespace { template - float getTotalWeight (const MWWorld::ContainerRefList& cellRefList) + float getTotalWeight (const MWWorld::CellRefList& cellRefList) { float sum = 0; - for (typename MWWorld::ContainerRefList::List::const_iterator iter ( + for (typename MWWorld::CellRefList::List::const_iterator iter ( cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) @@ -300,29 +300,29 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor ++*this; } -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Potion), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mPotion(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Apparatus), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mApparatus(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Armor), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mArmor(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Book), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mBook(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Clothing), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mClothing(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Probe), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mProbe(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Repair), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mRepair(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Weapon), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mWeapon(iterator){} void MWWorld::ContainerStoreIterator::incType() diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 63695c0df..e4f75d547 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -37,18 +37,18 @@ namespace MWWorld private: - MWWorld::ContainerRefList potions; - MWWorld::ContainerRefList appas; - MWWorld::ContainerRefList armors; - MWWorld::ContainerRefList books; - MWWorld::ContainerRefList clothes; - MWWorld::ContainerRefList ingreds; - MWWorld::ContainerRefList lights; - MWWorld::ContainerRefList lockpicks; - MWWorld::ContainerRefList miscItems; - MWWorld::ContainerRefList probes; - MWWorld::ContainerRefList repairs; - MWWorld::ContainerRefList weapons; + MWWorld::CellRefList potions; + MWWorld::CellRefList appas; + MWWorld::CellRefList armors; + MWWorld::CellRefList books; + MWWorld::CellRefList clothes; + MWWorld::CellRefList ingreds; + MWWorld::CellRefList lights; + MWWorld::CellRefList lockpicks; + MWWorld::CellRefList miscItems; + MWWorld::CellRefList probes; + MWWorld::CellRefList repairs; + MWWorld::CellRefList weapons; int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; @@ -120,18 +120,18 @@ namespace MWWorld ContainerStore *mContainer; mutable Ptr mPtr; - MWWorld::ContainerRefList::List::iterator mPotion; - MWWorld::ContainerRefList::List::iterator mApparatus; - MWWorld::ContainerRefList::List::iterator mArmor; - MWWorld::ContainerRefList::List::iterator mBook; - MWWorld::ContainerRefList::List::iterator mClothing; - MWWorld::ContainerRefList::List::iterator mIngredient; - MWWorld::ContainerRefList::List::iterator mLight; - MWWorld::ContainerRefList::List::iterator mLockpick; - MWWorld::ContainerRefList::List::iterator mMiscellaneous; - MWWorld::ContainerRefList::List::iterator mProbe; - MWWorld::ContainerRefList::List::iterator mRepair; - MWWorld::ContainerRefList::List::iterator mWeapon; + MWWorld::CellRefList::List::iterator mPotion; + MWWorld::CellRefList::List::iterator mApparatus; + MWWorld::CellRefList::List::iterator mArmor; + MWWorld::CellRefList::List::iterator mBook; + MWWorld::CellRefList::List::iterator mClothing; + MWWorld::CellRefList::List::iterator mIngredient; + MWWorld::CellRefList::List::iterator mLight; + MWWorld::CellRefList::List::iterator mLockpick; + MWWorld::CellRefList::List::iterator mMiscellaneous; + MWWorld::CellRefList::List::iterator mProbe; + MWWorld::CellRefList::List::iterator mRepair; + MWWorld::CellRefList::List::iterator mWeapon; private: @@ -142,18 +142,18 @@ namespace MWWorld ///< Begin-iterator // construct iterator using a CellRefList iterator - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::ContainerRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); void incType(); diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index 91622c354..5ec5ca9b5 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -17,9 +17,9 @@ namespace cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) { - if (!iter->second.mBase->mScript.empty() && iter->second.mData.getCount()) + if (!iter->mBase->mScript.empty() && iter->mData.getCount()) { - localScripts.add (iter->second.mBase->mScript, MWWorld::Ptr (&iter->second, cell)); + localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } } } @@ -34,7 +34,7 @@ namespace iter!=cellRefList.mList.end(); ++iter) { - MWWorld::Ptr containerPtr (&iter->second, cell); + MWWorld::Ptr containerPtr (&*iter, cell); MWWorld::ContainerStore& container = MWWorld::Class::get(containerPtr).getContainerStore(containerPtr); for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 768ca9e11..b917a8916 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -23,7 +23,7 @@ namespace if (!cellRefList.mList.empty()) { const MWWorld::Class& class_ = - MWWorld::Class::get (MWWorld::Ptr (&cellRefList.mList.begin()->second, &cell)); + MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); int numRefs = cellRefList.mList.size(); int current = 0; @@ -33,9 +33,9 @@ namespace MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; - if (it->second.mData.getCount() || it->second.mData.isEnabled()) + if (it->mData.getCount() || it->mData.isEnabled()) { - MWWorld::Ptr ptr (&it->second, &cell); + MWWorld::Ptr ptr (&*it, &cell); try { diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp new file mode 100644 index 000000000..005601cd1 --- /dev/null +++ b/apps/openmw/mwworld/store.cpp @@ -0,0 +1,65 @@ +#include "store.hpp" + +namespace MWWorld { + + +void Store::load(ESM::ESMReader &esm, const std::string &id) +{ + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded! So first, proceed as usual. + + // All cells have a name record, even nameless exterior cells. + std::string idLower = Misc::StringUtils::lowerCase(id); + ESM::Cell *cell = new ESM::Cell; + cell->mName = id; + + // The cell itself takes care of some of the hairy details + cell->load(esm, *mEsmStore); + + if(cell->mData.mFlags & ESM::Cell::Interior) + { + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(idLower)); + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // have new cell replace old cell + *oldcell = *cell; + } else + mInt[idLower] = *cell; + } + else + { + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); + if (oldcell) { + // push the new references on the list of references to manage + oldcell->mContextList.push_back(cell->mContextList.at(0)); + // copy list into new cell + cell->mContextList = oldcell->mContextList; + // merge lists of leased references, use newer data in case of conflict + for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) { + // remove reference from current leased ref tracker and add it to new cell + ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefnum); + if (itold != oldcell->mMovedRefs.end()) { + ESM::MovedCellRef target0 = *itold; + ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); + ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefnum); + wipecell->mLeasedRefs.erase(it_lease); + *itold = *it; + } + } + cell->mMovedRefs = oldcell->mMovedRefs; + // have new cell replace old cell + *oldcell = *cell; + } else + mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; + } + delete cell; +} + +} \ No newline at end of file diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index dbad7432f..cb18873cc 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,7 +187,7 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); - typename std::map::const_iterator it = mStatic.find(item.mId); + typename std::map::iterator it = mStatic.find(item.mId); if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { mStatic.erase(it); @@ -523,62 +523,12 @@ namespace MWWorld } } - void load(ESM::ESMReader &esm, const std::string &id) { - // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, - // and we merge all this data into one Cell object. However, we can't simply search for the cell id, - // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they - // are not available until both cells have been loaded! So first, proceed as usual. - - // All cells have a name record, even nameless exterior cells. - std::string idLower = Misc::StringUtils::lowerCase(id); - ESM::Cell *cell = new ESM::Cell; - cell->mName = id; - - // The cell itself takes care of all the hairy details - cell->load(esm, *mEsmStore); - - if(cell->mData.mFlags & ESM::Cell::Interior) - { - // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(idLower)); - if (oldcell) { - // push the new references on the list of references to manage - oldcell->mContextList.push_back(cell->mContextList.at(0)); - // copy list into new cell - cell->mContextList = oldcell->mContextList; - // have new cell replace old cell - *oldcell = *cell; - } else - mInt[idLower] = *cell; - } - else - { - // Store exterior cells by grid position, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(cell->getGridX(), cell->getGridY())); - if (oldcell) { - // push the new references on the list of references to manage - oldcell->mContextList.push_back(cell->mContextList.at(0)); - // copy list into new cell - cell->mContextList = oldcell->mContextList; - // merge lists of leased references, use newer data in case of conflict - for (ESM::MovedCellRefTracker::const_iterator it = cell->mMovedRefs.begin(); it != cell->mMovedRefs.end(); it++) { - // remove reference from current leased ref tracker and add it to new cell - if (oldcell->mMovedRefs.find(it->second.mRefnum) != oldcell->mMovedRefs.end()) { - ESM::MovedCellRef target0 = oldcell->mMovedRefs[it->second.mRefnum]; - ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - wipecell->mLeasedRefs.erase(it->second.mRefnum); - } - oldcell->mMovedRefs[it->second.mRefnum] = it->second; - } - cell->mMovedRefs = oldcell->mMovedRefs; - // have new cell replace old cell - *oldcell = *cell; - } else - mExt[std::make_pair(cell->mData.mX, cell->mData.mY)] = *cell; - } - delete cell; - } - + // HACK: Method implementation had to be moved to a separate cpp file, as we would otherwise get + // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. + // There some nasty three-way cyclic header dependency involved, which I could only fix by moving + // this method. + void load(ESM::ESMReader &esm, const std::string &id); + iterator intBegin() const { return iterator(mSharedInt.begin()); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 62b4f3037..db4fb67ff 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -33,13 +33,13 @@ namespace cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) { - if (!iter->second.mBase->mScript.empty() && iter->second.mData.getCount()) + if (!iter->mBase->mScript.empty() && iter->mData.getCount()) { - if (const ESM::Script *script = store.get().find (iter->second.mBase->mScript)) + if (const ESM::Script *script = store.get().find (iter->mBase->mScript)) { iter->mData.setLocals (*script); - localScripts.add (iter->second.mBase->mScript, MWWorld::Ptr (&iter->second, cell)); + localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } } } @@ -53,10 +53,10 @@ namespace for (iterator iter (refList.mList.begin()); iter!=refList.mList.end(); ++iter) { - if (iter->second.mData.getCount() > 0 && iter->second.mData.getBaseNode()){ - if (iter->second.mData.getHandle()==handle) + if (iter->mData.getCount() > 0 && iter->mData.getBaseNode()){ + if (iter->mData.getHandle()==handle) { - return &iter->second; + return &*iter; } } } @@ -1261,7 +1261,7 @@ namespace MWWorld CellRefList::List& refList = doors.mList; for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) { - MWWorld::LiveCellRef& ref = it->second; + MWWorld::LiveCellRef& ref = *it; if (ref.mRef.mTeleport) { diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 76a1e4f95..7400fd026 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -14,6 +14,17 @@ namespace ESM { +/// Some overloaded copare operators. +bool operator==(const MovedCellRef& ref, int pRefnum) +{ + return (ref.mRefnum == pRefnum); +} + +bool operator==(const CellRef& ref, int pRefnum) +{ + return (ref.mRefnum == pRefnum); +} + void CellRef::save(ESMWriter &esm) { esm.writeHNT("FRMR", mRefnum); @@ -134,13 +145,14 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) (int(*)(int)) std::tolower); // Add data required to make reference appear in the correct cell. - /* - std::cout << "Moving refnumber! First cell: " << mData.mX << " " << mData.mY << std::endl; - std::cout << " New cell: " << cMRef.mTarget[0] << " " << cMRef.mTarget[0] << std::endl; - std::cout << "Refnumber (MVRF): " << cMRef.mRefnum << " (FRMR) " << ref.mRefnum << std::endl; - */ - mMovedRefs[cMRef.mRefnum] = cMRef; - cellAlt->mLeasedRefs[ref.mRefnum] = ref; + // We should not need to test for duplicates, as this part of the code is pre-cell merge. + mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(ref); + else + *iter = ref; } // Save position of the cell references and move on diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 6862dbc5c..27bdd77ce 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -6,7 +6,7 @@ #include "esmcommon.hpp" #include "defs.hpp" -#include +#include "apps/openmw/mwbase/world.hpp" /* namespace MWWorld { @@ -95,24 +95,29 @@ public: }; /* Moved cell reference tracking object. This mainly stores the target cell - of the reference, so we can easily know where it has been moved when another - plugin tries to move it independently. - */ + of the reference, so we can easily know where it has been moved when another + plugin tries to move it independently. + Unfortunately, we need to implement this here. + */ class MovedCellRef { public: - int mRefnum; - - // Target cell (if exterior) - int mTarget[2]; - - // TODO: Support moving references between exterior and interior cells! - // This may happen in saves, when an NPC follows the player. Tribunal - // introduces a henchman (which no one uses), so we may need this as well. + int mRefnum; + + // Target cell (if exterior) + int mTarget[2]; + + // TODO: Support moving references between exterior and interior cells! + // This may happen in saves, when an NPC follows the player. Tribunal + // introduces a henchman (which no one uses), so we may need this as well. }; -typedef std::map MovedCellRefTracker; -typedef std::map CellRefTracker; +/// Overloaded copare operator used to search inside a list of cell refs. +bool operator==(const MovedCellRef& ref, int pRefnum); +bool operator==(const CellRef& ref, int pRefnum); + +typedef std::list MovedCellRefTracker; +typedef std::list CellRefTracker; /* Cells hold data about objects, creatures, statics (rocks, walls, buildings) and landscape (for exterior cells). Cells frequently From d40ee068975ec80a5acecc7ca686772a554106dd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 9 Feb 2013 15:25:50 +0100 Subject: [PATCH 585/916] fixed base/modified logic --- apps/opencs/model/world/columns.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fb94cbf59..cfbd804a5 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -17,9 +17,9 @@ namespace CSMWorld virtual void set (Record& record, const QVariant& data) { - ESXRecordT base = record.getBase(); - base.mValue = data.toFloat(); - record.setModified (base); + ESXRecordT record2 = record.get(); + record2.mValue = data.toFloat(); + record.setModified (record2); } virtual bool isEditable() const @@ -104,9 +104,9 @@ namespace CSMWorld virtual void set (Record& record, const QVariant& data) { - ESXRecordT base = record.getBase(); - base.mType = static_cast (data.toInt()); - record.setModified (base); + ESXRecordT record2 = record.get(); + record2.mType = static_cast (data.toInt()); + record.setModified (record2); } virtual bool isEditable() const @@ -134,18 +134,18 @@ namespace CSMWorld virtual void set (Record& record, const QVariant& data) { - ESXRecordT base = record.getBase(); + ESXRecordT record2 = record.get(); - switch (record.get().mType) + switch (record2.mType) { - case ESM::VT_String: base.mStr = data.toString().toUtf8().constData(); break; - case ESM::VT_Int: base.mI = data.toInt(); break; - case ESM::VT_Float: base.mF = data.toFloat(); break; + case ESM::VT_String: record2.mStr = data.toString().toUtf8().constData(); break; + case ESM::VT_Int: record2.mI = data.toInt(); break; + case ESM::VT_Float: record2.mF = data.toFloat(); break; default: break; } - record.setModified (base); + record.setModified (record2); } virtual bool isEditable() const From f197c67e95ac189b141ee65bf336b80648f9f3e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 12:46:20 -0800 Subject: [PATCH 586/916] Fix a circular include --- components/esm/loadcell.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 27bdd77ce..a811cab1c 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -3,17 +3,17 @@ #include #include +#include #include "esmcommon.hpp" #include "defs.hpp" -#include "apps/openmw/mwbase/world.hpp" -/* -namespace MWWorld { - class ESMStore; - class CellStore; + +namespace MWWorld +{ + class ESMStore; } -*/ + namespace ESM { From 8d6f017f171950ddcf64cfdf835677a519407f59 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 13:25:39 -0800 Subject: [PATCH 587/916] Remove an unneeded Animation field --- apps/openmw/mwrender/animation.cpp | 6 +----- apps/openmw/mwrender/animation.hpp | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 019217ca6..e157afc83 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -22,7 +22,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) - , mStartPosition(0.0f) , mLastPosition(0.0f) , mCurrentKeys(NULL) , mCurrentAnim(NULL) @@ -135,9 +134,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model { mAccumRoot = mInsert; mNonAccumRoot = skelinst->getBone(bone->getName()); - - mStartPosition = mNonAccumRoot->getInitialPosition(); - mLastPosition = mStartPosition; } } } @@ -243,7 +239,7 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(mStartPosition*mNonAccumRoot->_getDerivedScale() - mLastPosition); + mAccumRoot->setPosition(-mLastPosition * mAccumulate); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 62e93f110..ee73193bf 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -25,7 +25,6 @@ protected: Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; - Ogre::Vector3 mStartPosition; Ogre::Vector3 mLastPosition; std::vector mSkeletonSources; From f4e587c72c9019b388890d2da0a386bcd54228a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 17:48:23 -0800 Subject: [PATCH 588/916] Always create a skeleton from a NIF when there's more than one NiNode --- components/nifogre/ogre_nif_loader.cpp | 72 ++++++++++++++++---------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c7f6ac50d..5f7e686a0 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -21,8 +21,6 @@ */ -//loadResource->handleNode->handleNiTriShape->createSubMesh - #include "ogre_nif_loader.hpp" #include @@ -456,30 +454,28 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { + /* If the root node is a NiTriShape, or is a parent to only NiTriShapes, do + * not create a skeleton. */ if(node->recType == Nif::RC_NiTriShape) return false; - if(node->boneTrafo != NULL) + if(node->recType == Nif::RC_NiNode) { - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - skelMgr.create(name, group, true, &sLoaders[name]); - return true; + bool alltrishapes = true; + const Nif::NiNode *ninode = static_cast(node); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length() && alltrishapes;i++) + { + if(!children[i].empty() && children[i]->recType != Nif::RC_NiTriShape) + alltrishapes = false; + } + if(alltrishapes) + return false; } - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - if(createSkeleton(name, group, children[i].getPtr())) - return true; - } - } - } - return false; + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + skelMgr.create(name, group, true, &sLoaders[name]); + return true; } }; @@ -1052,7 +1048,7 @@ public: e = e->extra; } - if(node->recType == Nif::RC_NiTriShape) + if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = dynamic_cast(node); mShapeName = shape->name; @@ -1068,11 +1064,8 @@ public: { NIFMeshLoader *loader = &sLoaders[fullname]; *loader = *this; - if(!(flags&0x01)) // Not hidden - { - loader->mShapeIndex = shape->recIndex; - loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); - } + loader->mShapeIndex = shape->recIndex; + loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); @@ -1093,6 +1086,29 @@ public: } } } + + void createEmptyMesh(const Nif::Node *node, MeshInfoList &meshes) + { + /* This creates an empty mesh to which a skeleton gets attached. This + * is to ensure we have an entity with a skeleton instance, even if all + * other meshes are hidden or entities attached to a specific node + * instead of skinned. */ + std::string fullname = mName; + Misc::StringUtils::toLower(fullname); + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + Ogre::MeshPtr mesh = meshMgr.getByName(fullname); + if(mesh.isNull()) + { + NIFMeshLoader *loader = &sLoaders[fullname]; + *loader = *this; + + mesh = meshMgr.createManual(fullname, mGroup, loader); + mesh->setAutoBuildEdgeLists(false); + } + meshes.push_back(MeshInfo(mesh->getName(), (node->parent ? node->parent->name : node->name), + node->trafo.pos, node->trafo.rotation, node->trafo.scale)); + } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; @@ -1135,7 +1151,9 @@ MeshInfoList Loader::load(const std::string &name, const std::string &group) } NIFMeshLoader meshldr(name, group); - meshldr.createMeshes(node, meshes); + if(hasSkel) + meshldr.createEmptyMesh(node, meshes); + meshldr.createMeshes(node, meshes, 0); return meshes; } From 4ee5857bae1285a9334430e140b617ec37d4e05d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 9 Feb 2013 19:09:56 -0800 Subject: [PATCH 589/916] Filter accumulation axis for mLastPosition as needed --- apps/openmw/mwrender/animation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index e157afc83..9d9631ece 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -238,8 +238,8 @@ void Animation::reset(const std::string &marker) if(mNonAccumRoot) { - mLastPosition = mNonAccumRoot->getPosition(); - mAccumRoot->setPosition(-mLastPosition * mAccumulate); + mLastPosition = mNonAccumRoot->getPosition() * mAccumulate; + mAccumRoot->setPosition(-mLastPosition); } } From bba024d6ad5c2398ee57ff873fb092293d77f618 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Sun, 10 Feb 2013 08:37:45 +0400 Subject: [PATCH 590/916] Right mouse button click now stops Container GuiMode. --- apps/openmw/mwinput/inputmanagerimp.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8b..63afa3260 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -579,10 +579,14 @@ namespace MWInput // Toggle between game mode and inventory mode if(gameMode) mWindows.pushGuiMode(MWGui::GM_Inventory); - else if(mWindows.getMode() == MWGui::GM_Inventory) - mWindows.popGuiMode(); + else + { + MWGui::GuiMode mode = mWindows.getMode(); + if(mode == MWGui::GM_Inventory || mode == MWGui::GM_Container) + mWindows.popGuiMode(); + } - // .. but don't touch any other mode. + // .. but don't touch any other mode, except container. } void InputManager::toggleConsole() From 725bfe637218b4b87386f7bb7b385378556319d2 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Sun, 10 Feb 2013 08:50:36 +0400 Subject: [PATCH 591/916] TradeWindow: balance now changes per time if user holds +/- button pressed --- apps/openmw/mwgui/tradewindow.cpp | 51 +++++++++++++++++++++++--- apps/openmw/mwgui/tradewindow.hpp | 18 ++++++++- apps/openmw/mwgui/windowmanagerimp.cpp | 1 + 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 51eb3d87e..2cc8ff444 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -19,12 +19,17 @@ #include "inventorywindow.hpp" +static const float BALANCE_CHANGE_INITIAL_PAUSE = 0.5; // in seconds +static const float BALANCE_CHANGE_INTERVAL = 0.1; // in seconds + namespace MWGui { TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_trade_window.layout", parWindowManager) , ContainerBase(NULL) // no drag&drop , mCurrentBalance(0) + , mBalanceButtonsState(BBS_None) + , mBalanceChangePause(0.0) { MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; @@ -59,8 +64,10 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); - mIncreaseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonClicked); - mDecreaseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonClicked); + mIncreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonPressed); + mIncreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); + mDecreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonPressed); + mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); setCoord(400, 0, 400, 300); @@ -143,6 +150,21 @@ namespace MWGui } } + void TradeWindow::onFrame(float frameDuration) + { + if (!mMainWidget->getVisible() || mBalanceButtonsState == BBS_None) + return; + + mBalanceChangePause -= frameDuration; + if (mBalanceChangePause < 0.0) { + mBalanceChangePause += BALANCE_CHANGE_INTERVAL; + if (mBalanceButtonsState == BBS_Increase) + onIncreaseButtonTriggered(); + else if (mBalanceButtonsState == BBS_Decrease) + onDecreaseButtonTriggered(); + } + } + void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { const MWWorld::Store &gmst = @@ -242,7 +264,7 @@ namespace MWGui //skill use! MWWorld::Class::get(playerPtr).skillUsageSucceeded(playerPtr, ESM::Skill::Mercantile, 0); - } + } int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); @@ -271,14 +293,33 @@ namespace MWGui mWindowManager.removeGuiMode(GM_Barter); } - void TradeWindow::onIncreaseButtonClicked(MyGUI::Widget* _sender) + void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_Increase; + mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + onIncreaseButtonTriggered(); + } + + void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_Decrease; + mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + onDecreaseButtonTriggered(); + } + + void TradeWindow::onBalanceButtonReleased(MyGUI::Widget *_sender, int _left, int _top, MyGUI::MouseButton _id) + { + mBalanceButtonsState = BBS_None; + } + + void TradeWindow::onIncreaseButtonTriggered() { if(mCurrentBalance<=-1) mCurrentBalance -= 1; if(mCurrentBalance>=1) mCurrentBalance += 1; updateLabels(); } - void TradeWindow::onDecreaseButtonClicked(MyGUI::Widget* _sender) + void TradeWindow::onDecreaseButtonTriggered() { if(mCurrentBalance<-1) mCurrentBalance += 1; if(mCurrentBalance>1) mCurrentBalance -= 1; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 219e44036..20d9b6069 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -34,6 +34,8 @@ namespace MWGui void addOrRemoveGold(int gold); + void onFrame(float frameDuration); + protected: MyGUI::Button* mFilterAll; MyGUI::Button* mFilterWeapon; @@ -57,12 +59,24 @@ namespace MWGui int mCurrentBalance; int mCurrentMerchantOffer; + enum BalanceButtonsState { + BBS_None, + BBS_Increase, + BBS_Decrease + } mBalanceButtonsState; + /// pause before next balance change will trigger while user holds +/- button pressed + float mBalanceChangePause; + void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender); - void onIncreaseButtonClicked(MyGUI::Widget* _sender); - void onDecreaseButtonClicked(MyGUI::Widget* _sender); + void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + + void onIncreaseButtonTriggered(); + void onDecreaseButtonTriggered(); // don't show items that the NPC has equipped in his trade-window. virtual bool ignoreEquippedItems() { return true; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8ec495550..9663def5d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -608,6 +608,7 @@ void WindowManager::onFrame (float frameDuration) mHud->onFrame(frameDuration); mTrainingWindow->onFrame (frameDuration); + mTradeWindow->onFrame(frameDuration); mTrainingWindow->checkReferenceAvailable(); mDialogueWindow->checkReferenceAvailable(); From 59808c3e10e0088def9bb4c07f7a5efeb69ab1c6 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Sun, 10 Feb 2013 08:59:38 +0400 Subject: [PATCH 592/916] GUI: Birth and Class dialogs now both select 1st item in list at first time. --- apps/openmw/mwgui/birth.cpp | 16 +++++++++++----- apps/openmw/mwgui/class.cpp | 9 ++++++++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 4837821e0..99d6605d3 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -133,8 +133,6 @@ void BirthDialog::updateBirths() const MWWorld::Store &signs = MWBase::Environment::get().getWorld()->getStore().get(); - int index = 0; - // sort by name std::vector < std::pair > birthSigns; @@ -145,12 +143,20 @@ void BirthDialog::updateBirths() } std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); - for (std::vector < std::pair >::const_iterator it2 = birthSigns.begin(); it2 != birthSigns.end(); ++it2) + int index = 0; + for (std::vector >::const_iterator it2 = birthSigns.begin(); + it2 != birthSigns.end(); ++it2, ++index) { mBirthList->addItem(it2->second->mName, it2->first); - if (boost::iequals(it2->first, mCurrentBirthId)) + if (mCurrentBirthId.empty()) + { mBirthList->setIndexSelected(index); - ++index; + mCurrentBirthId = it2->first; + } + else if (boost::iequals(it2->first, mCurrentBirthId)) + { + mBirthList->setIndexSelected(index); + } } } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index c14c7f74b..475efaab3 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -197,8 +197,15 @@ void PickClassDialog::updateClasses() const std::string &id = it->mId; mClassList->addItem(it->mName, id); - if (boost::iequals(id, mCurrentClassId)) + if (mCurrentClassId.empty()) + { + mCurrentClassId = id; mClassList->setIndexSelected(index); + } + else if (boost::iequals(id, mCurrentClassId)) + { + mClassList->setIndexSelected(index); + } ++index; } } From e4ed397b2d35d77398a2d6596657b2a6eba67d74 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sun, 10 Feb 2013 14:02:06 +0100 Subject: [PATCH 593/916] Merge plugins and masters list view in openDialog. Simplify datafilesmodel. --- components/fileorderlist/datafileslist.cpp | 68 +---------- components/fileorderlist/datafileslist.hpp | 2 - .../fileorderlist/model/datafilesmodel.cpp | 108 +++--------------- .../fileorderlist/model/datafilesmodel.hpp | 17 +-- 4 files changed, 28 insertions(+), 167 deletions(-) diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index d25060baa..80d58b35f 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -48,8 +48,7 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) : QWidget(parent) , mCfgMgr(cfg) { - // Models - mMastersModel = new DataFilesModel(this); + // Model mPluginsModel = new DataFilesModel(this); mPluginsProxyModel = new QSortFilterProxyModel(); @@ -78,29 +77,6 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) QCheckBox checkBox; unsigned int height = checkBox.sizeHint().height() + 4; - mMastersTable = new QTableView(this); - mMastersTable->setModel(mMastersModel); - mMastersTable->setObjectName("MastersTable"); - mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection); - mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mMastersTable->setAlternatingRowColors(true); - mMastersTable->horizontalHeader()->setStretchLastSection(true); - mMastersTable->horizontalHeader()->hide(); - - // Set the row height to the size of the checkboxes - mMastersTable->verticalHeader()->setDefaultSectionSize(height); - mMastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mMastersTable->verticalHeader()->hide(); - mMastersTable->setColumnHidden(1, true); - mMastersTable->setColumnHidden(2, true); - mMastersTable->setColumnHidden(3, true); - mMastersTable->setColumnHidden(4, true); - mMastersTable->setColumnHidden(5, true); - mMastersTable->setColumnHidden(6, true); - mMastersTable->setColumnHidden(7, true); - mMastersTable->setColumnHidden(8, true); - mPluginsTable = new QTableView(this); mPluginsTable->setModel(mPluginsProxyModel); mPluginsTable->setObjectName("PluginsTable"); @@ -124,26 +100,14 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) mPluginsTable->setColumnHidden(7, true); mPluginsTable->setColumnHidden(8, true); - // Add both tables to a splitter - QSplitter *splitter = new QSplitter(this); - splitter->setOrientation(Qt::Horizontal); - splitter->addWidget(mMastersTable); - splitter->addWidget(mPluginsTable); - - // Adjust the default widget widths inside the splitter - QList sizeList; - sizeList << 175 << 200; - splitter->setSizes(sizeList); - QVBoxLayout *pageLayout = new QVBoxLayout(this); pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(splitter); + pageLayout->addWidget(mPluginsTable); connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - - connect(mMastersModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); + + connect(mPluginsModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); @@ -178,7 +142,6 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString { // Set the charset for reading the esm/esp files if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { - mMastersModel->setEncoding(encoding); mPluginsModel->setEncoding(encoding); } @@ -186,11 +149,9 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { QString path = QString::fromStdString(it->string()); path.remove(QChar('\"')); - mMastersModel->addMasters(path); - mPluginsModel->addPlugins(path); + mPluginsModel->addFiles(path); } - mMastersModel->sort(0); mPluginsModel->sort(0); // mMastersTable->sortByColumn(3, Qt::AscendingOrder); // mPluginsTable->sortByColumn(3, Qt::AscendingOrder); @@ -200,11 +161,6 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString void DataFilesList::selectedFiles(std::vector& paths) { - QStringList masterPaths = mMastersModel->checkedItemsPaths(); - foreach (const QString &path, masterPaths) - { - paths.push_back(path.toStdString()); - } QStringList pluginPaths = mPluginsModel->checkedItemsPaths(); foreach (const QString &path, pluginPaths) { @@ -281,19 +237,12 @@ void DataFilesList::setCheckState(QModelIndex index) : mPluginsModel->setCheckState(sourceIndex, Qt::Checked); } - if (object->objectName() == QLatin1String("MastersTable")) { - (mMastersModel->checkState(index) == Qt::Checked) - ? mMastersModel->setCheckState(index, Qt::Unchecked) - : mMastersModel->setCheckState(index, Qt::Checked); - } - return; } void DataFilesList::uncheckAll() { - mMastersModel->uncheckAll(); mPluginsModel->uncheckAll(); } @@ -338,14 +287,9 @@ void DataFilesList::setCheckState(const QString& element, Qt::CheckState state) { mPluginsModel->setCheckState(mPluginsModel->indexFromItem(file), Qt::Checked); } - else - { - file = mMastersModel->findItem(element); - mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); - } } QStringList DataFilesList::checkedFiles() { - return mMastersModel->checkedItems() + mPluginsModel->checkedItems(); + return mPluginsModel->checkedItems(); } \ No newline at end of file diff --git a/components/fileorderlist/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp index 4b158d316..64584d1fb 100644 --- a/components/fileorderlist/datafileslist.hpp +++ b/components/fileorderlist/datafileslist.hpp @@ -49,12 +49,10 @@ public slots: void refresh(); private: - DataFilesModel *mMastersModel; DataFilesModel *mPluginsModel; QSortFilterProxyModel *mPluginsProxyModel; - QTableView *mMastersTable; QTableView *mPluginsTable; QMenu *mContextMenu; diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 5bb199679..4c33a555f 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -159,7 +159,7 @@ Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const if (!file) return Qt::NoItemFlags; - if (mAvailableFiles.contains(file->fileName())) { + if (canBeChecked(file)) { if (index.column() == 0) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } else { @@ -212,7 +212,6 @@ bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, in QString name = item(index.row())->fileName(); mCheckStates[name] = static_cast(value.toInt()); - emit checkedItemsChanged(checkedItems(), uncheckedItems()); emit layoutChanged(); return true; } @@ -263,73 +262,12 @@ void DataFilesModel::addFile(EsmFile *file) emit endInsertRows(); } -void DataFilesModel::addMasters(const QString &path) +void DataFilesModel::addFiles(const QString &path) { QDir dir(path); - dir.setNameFilters(QStringList(QLatin1String("*.esp"))); - - // Read the dependencies from the plugins - foreach (const QString &path, dir.entryList()) { - try { - ESM::ESMReader fileReader; - ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString())); - fileReader.setEncoder(&encoder); - fileReader.open(dir.absoluteFilePath(path).toStdString()); - - ESM::ESMReader::MasterList mlist = fileReader.getMasters(); - - for (unsigned int i = 0; i < mlist.size(); ++i) { - QString master = QString::fromStdString(mlist[i].name); - - // Add the plugin to the internal dependency map - mDependencies[master].append(path); - - // Don't add esps - if (master.endsWith(".esp", Qt::CaseInsensitive)) - continue; - - QFileInfo info(dir.absoluteFilePath(master)); - - EsmFile *file = new EsmFile(master); - file->setDates(info.lastModified(), info.lastRead()); - file->setPath(info.absoluteFilePath()); - - // Add the master to the table - if (findItem(master) == 0) - addFile(file); - - - } - - } catch(std::runtime_error &e) { - // An error occurred while reading the .esp - qWarning() << "Error reading esp: " << e.what(); - continue; - } - } - - // See if the masters actually exist in the filesystem - dir.setNameFilters(QStringList(QLatin1String("*.esm"))); - - foreach (const QString &path, dir.entryList()) { - QFileInfo info(dir.absoluteFilePath(path)); - - if (findItem(path) == 0) { - EsmFile *file = new EsmFile(path); - file->setDates(info.lastModified(), info.lastRead()); - - addFile(file); - } - - // Make the master selectable - mAvailableFiles.append(path); - } -} - -void DataFilesModel::addPlugins(const QString &path) -{ - QDir dir(path); - dir.setNameFilters(QStringList(QLatin1String("*.esp"))); + QStringList filters; + filters << "*.esp" << "*.esm"; + dir.setNameFilters(filters); foreach (const QString &path, dir.entryList()) { QFileInfo info(dir.absoluteFilePath(path)); @@ -347,9 +285,6 @@ void DataFilesModel::addPlugins(const QString &path) for (unsigned int i = 0; i < mlist.size(); ++i) { QString master = QString::fromStdString(mlist[i].name); masters.append(master); - - // Add the plugin to the internal dependency map - mDependencies[master].append(path); } file->setAuthor(QString::fromStdString(fileReader.getAuthor())); @@ -421,7 +356,7 @@ QStringList DataFilesModel::checkedItems() QString name = file->fileName(); // Only add the items that are in the checked list and available - if (mCheckStates[name] == Qt::Checked && mAvailableFiles.contains(name)) + if (mCheckStates[name] == Qt::Checked && canBeChecked(file)) list << name; } @@ -439,8 +374,8 @@ QStringList DataFilesModel::checkedItemsPaths() for (it = mFiles.constBegin(); it != itEnd; ++it) { EsmFile *file = item(i); ++i; - - if (mCheckStates[file->fileName()] == Qt::Checked && mAvailableFiles.contains(file->fileName())) + + if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file)) list << file->path(); } @@ -475,24 +410,17 @@ QStringList DataFilesModel::uncheckedItems() return list; } -void DataFilesModel::slotcheckedItemsChanged(const QStringList &checkedItems, const QStringList &unCheckedItems) +bool DataFilesModel::canBeChecked(EsmFile *file) const { - emit layoutAboutToBeChanged(); - - QStringList list; - - foreach (const QString &file, checkedItems) { - list << mDependencies[file]; - } - - foreach (const QString &file, unCheckedItems) { - foreach (const QString &remove, mDependencies[file]) { - list.removeAll(remove); + //element can be checked if all its dependencies are + bool canBeChecked = true; + foreach (const QString &master, file->masters()) + { + if (!mCheckStates.contains(master) || mCheckStates[master] != Qt::Checked) + { + canBeChecked = false; + break; } } - - mAvailableFiles.clear(); - mAvailableFiles.append(list); - - emit layoutChanged(); + return canBeChecked; } diff --git a/components/fileorderlist/model/datafilesmodel.hpp b/components/fileorderlist/model/datafilesmodel.hpp index adc80eac2..0e5008abe 100644 --- a/components/fileorderlist/model/datafilesmodel.hpp +++ b/components/fileorderlist/model/datafilesmodel.hpp @@ -34,10 +34,7 @@ public: void setEncoding(const QString &encoding); - void addFile(EsmFile *file); - - void addMasters(const QString &path); - void addPlugins(const QString &path); + void addFiles(const QString &path); void uncheckAll(); @@ -51,18 +48,12 @@ public: QModelIndex indexFromItem(EsmFile *item) const; EsmFile* findItem(const QString &name); EsmFile* item(int row) const; - -signals: - void checkedItemsChanged(const QStringList checkedItems, const QStringList unCheckedItems); - -public slots: - void slotcheckedItemsChanged(const QStringList &checkedItems, const QStringList &unCheckedItems); private: + bool canBeChecked(EsmFile *file) const; + void addFile(EsmFile *file); + QList mFiles; - QStringList mAvailableFiles; - - QHash mDependencies; QHash mCheckStates; QString mEncoding; From 0df7c7e5c17aff76fab9c4352a1904271c99c731 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sun, 10 Feb 2013 14:08:54 +0100 Subject: [PATCH 594/916] Rename mPlugins* to mFiles* --- components/fileorderlist/datafileslist.cpp | 108 ++++++++++----------- components/fileorderlist/datafileslist.hpp | 6 +- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index 80d58b35f..5ea2e051d 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -49,11 +49,11 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) , mCfgMgr(cfg) { // Model - mPluginsModel = new DataFilesModel(this); + mFilesModel = new DataFilesModel(this); - mPluginsProxyModel = new QSortFilterProxyModel(); - mPluginsProxyModel->setDynamicSortFilter(true); - mPluginsProxyModel->setSourceModel(mPluginsModel); + mFilesProxyModel = new QSortFilterProxyModel(); + mFilesProxyModel->setDynamicSortFilter(true); + mFilesProxyModel->setSourceModel(mFilesModel); // Filter toolbar QLabel *filterLabel = new QLabel(tr("&Filter:"), this); @@ -77,41 +77,41 @@ DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) QCheckBox checkBox; unsigned int height = checkBox.sizeHint().height() + 4; - mPluginsTable = new QTableView(this); - mPluginsTable->setModel(mPluginsProxyModel); - mPluginsTable->setObjectName("PluginsTable"); - mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); - mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mPluginsTable->setSelectionMode(QAbstractItemView::SingleSelection); - mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mPluginsTable->setAlternatingRowColors(true); - mPluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); - mPluginsTable->horizontalHeader()->setStretchLastSection(true); - mPluginsTable->horizontalHeader()->hide(); + mFilesTable = new QTableView(this); + mFilesTable->setModel(mFilesProxyModel); + mFilesTable->setObjectName("PluginsTable"); + mFilesTable->setContextMenuPolicy(Qt::CustomContextMenu); + mFilesTable->setSelectionBehavior(QAbstractItemView::SelectRows); + mFilesTable->setSelectionMode(QAbstractItemView::SingleSelection); + mFilesTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + mFilesTable->setAlternatingRowColors(true); + mFilesTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); + mFilesTable->horizontalHeader()->setStretchLastSection(true); + mFilesTable->horizontalHeader()->hide(); - mPluginsTable->verticalHeader()->setDefaultSectionSize(height); - mPluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mPluginsTable->setColumnHidden(1, true); - mPluginsTable->setColumnHidden(2, true); - mPluginsTable->setColumnHidden(3, true); - mPluginsTable->setColumnHidden(4, true); - mPluginsTable->setColumnHidden(5, true); - mPluginsTable->setColumnHidden(6, true); - mPluginsTable->setColumnHidden(7, true); - mPluginsTable->setColumnHidden(8, true); + mFilesTable->verticalHeader()->setDefaultSectionSize(height); + mFilesTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + mFilesTable->setColumnHidden(1, true); + mFilesTable->setColumnHidden(2, true); + mFilesTable->setColumnHidden(3, true); + mFilesTable->setColumnHidden(4, true); + mFilesTable->setColumnHidden(5, true); + mFilesTable->setColumnHidden(6, true); + mFilesTable->setColumnHidden(7, true); + mFilesTable->setColumnHidden(8, true); QVBoxLayout *pageLayout = new QVBoxLayout(this); pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(mPluginsTable); + pageLayout->addWidget(mFilesTable); - connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(mFilesTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mPluginsModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mPluginsModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); + connect(mFilesModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mFilesModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(mFilesTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); createActions(); } @@ -142,17 +142,17 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString { // Set the charset for reading the esm/esp files if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { - mPluginsModel->setEncoding(encoding); + mFilesModel->setEncoding(encoding); } // Add the paths to the respective models for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { QString path = QString::fromStdString(it->string()); path.remove(QChar('\"')); - mPluginsModel->addFiles(path); + mFilesModel->addFiles(path); } - mPluginsModel->sort(0); + mFilesModel->sort(0); // mMastersTable->sortByColumn(3, Qt::AscendingOrder); // mPluginsTable->sortByColumn(3, Qt::AscendingOrder); @@ -161,7 +161,7 @@ bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString void DataFilesList::selectedFiles(std::vector& paths) { - QStringList pluginPaths = mPluginsModel->checkedItemsPaths(); + QStringList pluginPaths = mFilesModel->checkedItemsPaths(); foreach (const QString &path, pluginPaths) { paths.push_back(path.toStdString()); @@ -171,11 +171,11 @@ void DataFilesList::selectedFiles(std::vector& paths) void DataFilesList::check() { // Check the current selection - if (!mPluginsTable->selectionModel()->hasSelection()) { + if (!mFilesTable->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); //sort selection ascending because selectedIndexes returns an unsorted list //qSort(indexes.begin(), indexes.end(), rowSmallerThan); @@ -184,18 +184,18 @@ void DataFilesList::check() if (!index.isValid()) return; - mPluginsModel->setCheckState(index, Qt::Checked); + mFilesModel->setCheckState(index, Qt::Checked); } } void DataFilesList::uncheck() { // uncheck the current selection - if (!mPluginsTable->selectionModel()->hasSelection()) { + if (!mFilesTable->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); //sort selection ascending because selectedIndexes returns an unsorted list //qSort(indexes.begin(), indexes.end(), rowSmallerThan); @@ -204,17 +204,17 @@ void DataFilesList::uncheck() if (!index.isValid()) return; - mPluginsModel->setCheckState(index, Qt::Unchecked); + mFilesModel->setCheckState(index, Qt::Unchecked); } } void DataFilesList::refresh() { - mPluginsModel->sort(0); + mFilesModel->sort(0); // Refresh the plugins table - mPluginsTable->scrollToTop(); + mFilesTable->scrollToTop(); } @@ -230,11 +230,11 @@ void DataFilesList::setCheckState(QModelIndex index) return; if (object->objectName() == QLatin1String("PluginsTable")) { - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(index); + QModelIndex sourceIndex = mFilesProxyModel->mapToSource(index); - (mPluginsModel->checkState(sourceIndex) == Qt::Checked) - ? mPluginsModel->setCheckState(sourceIndex, Qt::Unchecked) - : mPluginsModel->setCheckState(sourceIndex, Qt::Checked); + (mFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mFilesModel->setCheckState(sourceIndex, Qt::Checked); } return; @@ -243,25 +243,25 @@ void DataFilesList::setCheckState(QModelIndex index) void DataFilesList::uncheckAll() { - mPluginsModel->uncheckAll(); + mFilesModel->uncheckAll(); } void DataFilesList::filterChanged(const QString filter) { QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); - mPluginsProxyModel->setFilterRegExp(regExp); + mFilesProxyModel->setFilterRegExp(regExp); } void DataFilesList::showContextMenu(const QPoint &point) { // Make sure there are plugins in the view - if (!mPluginsTable->selectionModel()->hasSelection()) { + if (!mFilesTable->selectionModel()->hasSelection()) { return; } - QPoint globalPos = mPluginsTable->mapToGlobal(point); + QPoint globalPos = mFilesTable->mapToGlobal(point); - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); // Show the check/uncheck actions depending on the state of the selected items mUncheckAction->setEnabled(false); @@ -271,7 +271,7 @@ void DataFilesList::showContextMenu(const QPoint &point) if (!index.isValid()) return; - (mPluginsModel->checkState(index) == Qt::Checked) + (mFilesModel->checkState(index) == Qt::Checked) ? mUncheckAction->setEnabled(true) : mCheckAction->setEnabled(true); } @@ -282,14 +282,14 @@ void DataFilesList::showContextMenu(const QPoint &point) void DataFilesList::setCheckState(const QString& element, Qt::CheckState state) { - EsmFile *file = mPluginsModel->findItem(element); + EsmFile *file = mFilesModel->findItem(element); if (file) { - mPluginsModel->setCheckState(mPluginsModel->indexFromItem(file), Qt::Checked); + mFilesModel->setCheckState(mFilesModel->indexFromItem(file), Qt::Checked); } } QStringList DataFilesList::checkedFiles() { - return mPluginsModel->checkedItems(); + return mFilesModel->checkedItems(); } \ No newline at end of file diff --git a/components/fileorderlist/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp index 64584d1fb..69a20393c 100644 --- a/components/fileorderlist/datafileslist.hpp +++ b/components/fileorderlist/datafileslist.hpp @@ -49,11 +49,11 @@ public slots: void refresh(); private: - DataFilesModel *mPluginsModel; + DataFilesModel *mFilesModel; - QSortFilterProxyModel *mPluginsProxyModel; + QSortFilterProxyModel *mFilesProxyModel; - QTableView *mPluginsTable; + QTableView *mFilesTable; QMenu *mContextMenu; From 158c6fc9fad2c8e3447e42bd495891d53ea1fbcb Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 10 Feb 2013 14:58:46 +0000 Subject: [PATCH 595/916] pressing enter when a messagebox is prompting for "ok", will activate ok button --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/messagebox.cpp | 24 ++++++++++++++++++++++++ apps/openmw/mwgui/messagebox.hpp | 6 +++++- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 13 ++++++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ 7 files changed, 50 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 30bfced06..4f7435fad 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -199,6 +199,7 @@ namespace MWBase ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons) = 0; + virtual void enterPressed () = 0; virtual int readPressedButton() = 0; ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index b660af7dd..08f950868 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -1,3 +1,5 @@ +#include + #include "messagebox.hpp" using namespace MWGui; @@ -133,6 +135,10 @@ void MessageBoxManager::setMessageBoxSpeed (int speed) mMessageBoxSpeed = speed; } +void MessageBoxManager::enterPressed () +{ + mInterMessageBoxe->enterPressed(); +} int MessageBoxManager::readPressedButton () { @@ -359,7 +365,25 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan } } +void InteractiveMessageBox::enterPressed() +{ + + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) + buttonActivated(*button); + } + +} + void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) +{ + buttonActivated (pressed); +} + +void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) { mMarkedToDelete = true; int index = 0; diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 5e4c468d5..4be8bc5b7 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -34,7 +34,8 @@ namespace MWGui void removeMessageBox (float time, MessageBox *msgbox); bool removeMessageBox (MessageBox *msgbox); void setMessageBoxSpeed (int speed); - + + void enterPressed(); int readPressedButton (); MWBase::WindowManager *mWindowManager; @@ -70,12 +71,15 @@ namespace MWGui { public: InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons); + void enterPressed (); void mousePressed (MyGUI::Widget* _widget); int readPressedButton (); bool mMarkedToDelete; private: + void buttonActivated (MyGUI::Widget* _widget); + MessageBoxManager& mMessageBoxManager; MyGUI::EditPtr mMessageWidget; MyGUI::WidgetPtr mButtonsWidget; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8ec495550..ae314dd68 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -560,6 +560,11 @@ void WindowManager::messageBox (const std::string& message, const std::vectorenterPressed(); +} + int WindowManager::readPressedButton () { return mMessageBoxManager->readPressedButton(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8bcb88e22..fff627366 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -189,6 +189,7 @@ namespace MWGui virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons); + virtual void enterPressed (); virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual void onFrame (float frameDuration); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1f270df8b..153bbba8d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -51,6 +51,7 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) + , mEnterPressed(false) { Ogre::RenderWindow* window = ogre.getWindow (); size_t windowHnd; @@ -239,6 +240,10 @@ namespace MWInput void InputManager::update(float dt, bool loading) { + // Pressing enter when a messagebox is prompting for "ok" will activate the ok button + if(mEnterPressed && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox) + MWBase::Environment::get().getWindowManager()->enterPressed(); + // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); @@ -251,7 +256,7 @@ namespace MWInput // update values of channels (as a result of pressed keys) if (!loading) mInputCtrl->update(dt); - + // Update windows/gui as a result of input events // For instance this could mean opening a new window/dialog, // by doing this after the input events are handled we @@ -426,6 +431,9 @@ namespace MWInput bool InputManager::keyPressed( const OIS::KeyEvent &arg ) { + if(arg.key == OIS::KC_RETURN && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console) + mEnterPressed = true; + mInputCtrl->keyPressed (arg); unsigned int text = arg.text; #ifdef __APPLE__ // filter \016 symbol for F-keys on OS X @@ -442,6 +450,9 @@ namespace MWInput bool InputManager::keyReleased( const OIS::KeyEvent &arg ) { + if(arg.key == OIS::KC_RETURN) + mEnterPressed = false; + mInputCtrl->keyReleased (arg); MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key)); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f28..c7ba7b756 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -151,6 +151,8 @@ namespace MWInput std::map mControlSwitch; + bool mEnterPressed; + private: void adjustMouseRegion(int width, int height); From c32c31f6d642c38450b03076319d7d73d72b161c Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 10 Feb 2013 15:41:02 +0000 Subject: [PATCH 596/916] break after activating button --- apps/openmw/mwgui/messagebox.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 08f950868..896ab3bb5 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -373,7 +373,10 @@ void InteractiveMessageBox::enterPressed() for(button = mButtons.begin(); button != mButtons.end(); ++button) { if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) + { buttonActivated(*button); + break; + } } } From eb6590f7d88ef0027bb3ab59c44cd2507168c457 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 10 Feb 2013 17:21:25 +0100 Subject: [PATCH 597/916] added delegate factory --- apps/opencs/view/doc/viewmanager.cpp | 6 +++- apps/opencs/view/doc/viewmanager.hpp | 6 ++++ apps/opencs/view/world/table.cpp | 7 +++- apps/opencs/view/world/util.cpp | 53 ++++++++++++++++++++++++++++ apps/opencs/view/world/util.hpp | 48 +++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index b01b9ce34..2a6309da1 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -6,6 +6,8 @@ #include "../../model/doc/documentmanager.hpp" #include "../../model/doc/document.hpp" +#include "../world/util.hpp" + #include "view.hpp" void CSVDoc::ViewManager::updateIndices() @@ -29,11 +31,13 @@ void CSVDoc::ViewManager::updateIndices() CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager) { - + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; } CSVDoc::ViewManager::~ViewManager() { + delete mDelegateFactories; + for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; } diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 91a80d496..72e7a3e1a 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -11,6 +11,11 @@ namespace CSMDoc class DocumentManager; } +namespace CSVWorld +{ + class CommandDelegateFactoryCollection; +} + namespace CSVDoc { class View; @@ -21,6 +26,7 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; + CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; // not implemented ViewManager (const ViewManager&); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 0721ead2c..f9167d259 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -102,7 +102,12 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q if (flags & CSMWorld::ColumnBase::Flag_Table) { - CommandDelegate *delegate = new CommandDelegate (undoStack, this); + CSMWorld::ColumnBase::Display display = static_cast ( + mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); + + CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display, + undoStack, this); + mDelegates.push_back (delegate); setItemDelegateForColumn (i, delegate); } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 7181dd4d1..85fda2dad 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -1,6 +1,8 @@ #include "util.hpp" +#include + #include #include "../../model/world/commands.hpp" @@ -35,6 +37,57 @@ QVariant CSVWorld::NastyTableModelHack::getData() const return mData; } + +CSVWorld::CommandDelegateFactory::~CommandDelegateFactory() {} + + +CSVWorld::CommandDelegateFactoryCollection *CSVWorld::CommandDelegateFactoryCollection::sThis = 0; + +CSVWorld::CommandDelegateFactoryCollection::CommandDelegateFactoryCollection() +{ + if (sThis) + throw std::logic_error ("multiple instances of CSVWorld::CommandDelegateFactoryCollection"); + + sThis = this; +} + +CSVWorld::CommandDelegateFactoryCollection::~CommandDelegateFactoryCollection() +{ + sThis = 0; + + for (std::map::iterator iter ( + mFactories.begin()); + iter!=mFactories.end(); ++iter) + delete iter->second; +} + +void CSVWorld::CommandDelegateFactoryCollection::add (CSMWorld::ColumnBase::Display display, + CommandDelegateFactory *factory) +{ + mFactories.insert (std::make_pair (display, factory)); +} + +CSVWorld::CommandDelegate *CSVWorld::CommandDelegateFactoryCollection::makeDelegate ( + CSMWorld::ColumnBase::Display display, QUndoStack& undoStack, QObject *parent) const +{ + std::map::const_iterator iter = + mFactories.find (display); + + if (iter!=mFactories.end()) + return iter->second->makeDelegate (undoStack, parent); + + return new CommandDelegate (undoStack, parent); +} + +const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFactoryCollection::get() +{ + if (!sThis) + throw std::logic_error ("no instance of CSVWorld::CommandDelegateFactoryCollection"); + + return *sThis; +} + + CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) : QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) {} diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 136583118..79f30da2c 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -1,9 +1,13 @@ #ifndef CSV_WORLD_UTIL_H #define CSV_WORLD_UTIL_H +#include + #include #include +#include "../../model/world/columnbase.hpp" + class QUndoStack; namespace CSVWorld @@ -31,6 +35,50 @@ namespace CSVWorld QVariant getData() const; }; + class CommandDelegate; + + class CommandDelegateFactory + { + public: + + virtual ~CommandDelegateFactory(); + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const = 0; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + }; + + class CommandDelegateFactoryCollection + { + static CommandDelegateFactoryCollection *sThis; + std::map mFactories; + + private: + + // not implemented + CommandDelegateFactoryCollection (const CommandDelegateFactoryCollection&); + CommandDelegateFactoryCollection& operator= (const CommandDelegateFactoryCollection&); + + public: + + CommandDelegateFactoryCollection(); + + ~CommandDelegateFactoryCollection(); + + void add (CSMWorld::ColumnBase::Display display, CommandDelegateFactory *factory); + ///< The ownership of \æ factory is transferred to *this. + /// + /// This function must not be called more than once per value of \æ display. + + CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, QUndoStack& undoStack, + QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + /// + /// If no factory is registered for \a display, a CommandDelegate will be returned. + + static const CommandDelegateFactoryCollection& get(); + + }; + ///< \brief Use commands instead of manipulating the model directly class CommandDelegate : public QStyledItemDelegate { From f4d60ae7b203b90c9714fff9fa81eb06a79f278e Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Sun, 10 Feb 2013 19:59:25 +0100 Subject: [PATCH 598/916] Files sorting (masters then plugins). Remove unneeded includes. --- apps/launcher/datafilespage.cpp | 7 --- components/fileorderlist/datafileslist.cpp | 1 - .../fileorderlist/model/datafilesmodel.cpp | 44 +++++-------------- .../fileorderlist/model/esm/esmfile.hpp | 18 ++++---- 4 files changed, 21 insertions(+), 49 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 52b8c9cbe..8afece00b 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -7,12 +7,7 @@ #include #include -////#include "model/datafilesmodel.hpp" -////#include "model/esm/esmfile.hpp" - #include "utils/profilescombobox.hpp" -////#include "utils/filedialog.hpp" -////#include "utils/naturalsort.hpp" #include "utils/textinputdialog.hpp" #include "datafilespage.hpp" @@ -527,7 +522,5 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); mDataFilesList->uncheckAll(); - ////mMastersModel->uncheckAll(); - ////mPluginsModel->uncheckAll(); readConfig(); } diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp index 5ea2e051d..2f1b555c1 100644 --- a/components/fileorderlist/datafileslist.cpp +++ b/components/fileorderlist/datafileslist.cpp @@ -8,7 +8,6 @@ #include "utils/filedialog.hpp" #include "utils/lineedit.hpp" -#include "utils/naturalsort.hpp" #include "datafileslist.hpp" diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 4c33a555f..682ef0128 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -8,8 +8,6 @@ #include "esm/esmfile.hpp" -#include "../utils/naturalsort.hpp" - #include "datafilesmodel.hpp" DataFilesModel::DataFilesModel(QObject *parent) : @@ -219,39 +217,21 @@ bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, in return false; } +bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2) +{ + //Masters first then alphabetically + if (e1->fileName().endsWith(".esm") && !e2->fileName().endsWith(".esm")) + return true; + if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) + return false; + + return e1->fileName().toLower() < e2->fileName().toLower(); +} + void DataFilesModel::sort(int column, Qt::SortOrder order) { - // TODO: Make this more efficient emit layoutAboutToBeChanged(); - - QList sortedFiles; - - QMultiMap timestamps; - - foreach (EsmFile *file, mFiles) - timestamps.insert(file->modified().toString(Qt::ISODate), file->fileName()); - - QMapIterator ti(timestamps); - - while (ti.hasNext()) { - ti.next(); - - QModelIndex index = indexFromItem(findItem(ti.value())); - - if (!index.isValid()) - continue; - - EsmFile *file = item(index.row()); - - if (!file) - continue; - - sortedFiles.append(file); - } - - mFiles.clear(); - mFiles = sortedFiles; - + qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile); emit layoutChanged(); } diff --git a/components/fileorderlist/model/esm/esmfile.hpp b/components/fileorderlist/model/esm/esmfile.hpp index ad267aa75..52b3fbd00 100644 --- a/components/fileorderlist/model/esm/esmfile.hpp +++ b/components/fileorderlist/model/esm/esmfile.hpp @@ -26,15 +26,15 @@ public: void setMasters(const QStringList &masters); void setDescription(const QString &description); - inline QString fileName() { return mFileName; } - inline QString author() { return mAuthor; } - inline int size() { return mSize; } - inline QDateTime modified() { return mModified; } - inline QDateTime accessed() { return mAccessed; } - inline float version() { return mVersion; } - inline QString path() { return mPath; } - inline QStringList masters() { return mMasters; } - inline QString description() { return mDescription; } + inline QString fileName() const { return mFileName; } + inline QString author() const { return mAuthor; } + inline int size() const { return mSize; } + inline QDateTime modified() const { return mModified; } + inline QDateTime accessed() const { return mAccessed; } + inline float version() const { return mVersion; } + inline QString path() const { return mPath; } + inline QStringList masters() const { return mMasters; } + inline QString description() const { return mDescription; } private: From 62c711d709d9c3bf314b97bd31b198f3768255e9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 11 Feb 2013 02:28:02 +0100 Subject: [PATCH 599/916] Small change to delete microcode cache more aggressively. --- extern/shiny/Main/Factory.cpp | 18 +++++++++++------- extern/shiny/Main/Factory.hpp | 5 ++++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/extern/shiny/Main/Factory.cpp b/extern/shiny/Main/Factory.cpp index 21f13e30b..40c695fd4 100644 --- a/extern/shiny/Main/Factory.cpp +++ b/extern/shiny/Main/Factory.cpp @@ -15,6 +15,7 @@ namespace sh { Factory* Factory::sThis = 0; + const std::string Factory::mBinaryCacheName = "binaryCache"; Factory& Factory::getInstance() { @@ -198,16 +199,16 @@ namespace sh if (mShadersLastModified[sourceRelative] != lastModified) { // delete any outdated shaders based on this shader set - removeCache (it->first); - // remove the whole binary cache (removing only the individual shaders does not seem to be possible at this point with OGRE) - removeBinaryCache = true; + if (removeCache (it->first)) + removeBinaryCache = true; } } else { // if we get here, this is either the first run or a new shader file was added // in both cases we can safely delete - removeCache (it->first); + if (removeCache (it->first)) + removeBinaryCache = true; } mShaderSets.insert(std::make_pair(it->first, newSet)); } @@ -304,7 +305,7 @@ namespace sh if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache) { - std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; + std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; if (boost::filesystem::exists(file)) { mPlatform->deserializeShaders (file); @@ -316,7 +317,7 @@ namespace sh { if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache) { - std::string file = mPlatform->getCacheFolder () + "/shShaderCache.txt"; + std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName; mPlatform->serializeShaders (file); } @@ -590,8 +591,9 @@ namespace sh m->createForConfiguration (configuration, 0); } - void Factory::removeCache(const std::string& pattern) + bool Factory::removeCache(const std::string& pattern) { + bool ret = false; if ( boost::filesystem::exists(mPlatform->getCacheFolder()) && boost::filesystem::is_directory(mPlatform->getCacheFolder())) { @@ -620,10 +622,12 @@ namespace sh if (shaderName == pattern) { boost::filesystem::remove(file); + ret = true; std::cout << "Removing outdated shader: " << file << std::endl; } } } } + return ret; } } diff --git a/extern/shiny/Main/Factory.hpp b/extern/shiny/Main/Factory.hpp index 6d4175c97..846860b89 100644 --- a/extern/shiny/Main/Factory.hpp +++ b/extern/shiny/Main/Factory.hpp @@ -203,7 +203,10 @@ namespace sh MaterialInstance* findInstance (const std::string& name); MaterialInstance* searchInstance (const std::string& name); - void removeCache (const std::string& pattern); + /// @return was anything removed? + bool removeCache (const std::string& pattern); + + static const std::string mBinaryCacheName; }; } From 55dd17c27c81268916b6045e828029cd4ed31c2f Mon Sep 17 00:00:00 2001 From: graffy76 Date: Mon, 11 Feb 2013 04:30:16 -0600 Subject: [PATCH 600/916] Added setBarColor() function to CSVDoc::Operation. Created four color types for existing operations (save, verify, compile and search), with a default for future / undefined ops. --- apps/opencs/view/doc/operation.cpp | 70 +++++++++++++++++++++++++++++- apps/opencs/view/doc/operation.hpp | 6 ++- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index 3f415da03..c301195bc 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -35,7 +35,7 @@ void CSVDoc::Operation::updateLabel (int threads) CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) { /// \todo Add a cancel button or a pop up menu with a cancel item - + setBarColor( type); updateLabel(); /// \todo assign different progress bar colours to allow the user to distinguish easily between operation types @@ -51,4 +51,70 @@ void CSVDoc::Operation::setProgress (int current, int max, int threads) int CSVDoc::Operation::getType() const { return mType; -} \ No newline at end of file +} + +void CSVDoc::Operation::setBarColor (int type) +{ + QString style ="QProgressBar {" + "text-align: center;" + "}" + "QProgressBar::chunk {" + "background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 %1, stop:.50 %2 stop: .51 %3 stop:1 %4);" + "text-align: center;" + "margin: 2px 1px 1p 2px;" + "}"; + + // "QProgressBar::chunk {background-color: %1;}"; + + QString topColor = "#F2F6F8"; + QString bottomColor = "#E0EFF9"; + QString midTopColor = "#D8E1E7"; + QString midBottomColor = "#B5C6D0"; // default gray gloss + + // colors inspired by samples from: + // http://www.colorzilla.com/gradient-editor/ + + switch (type) + { + case CSMDoc::State_Saving: + + topColor = "#FECCB1"; + midTopColor = "#F17432"; + midBottomColor = "#EA5507"; + bottomColor = "#FB955E"; // red gloss #2 + //break; + + case CSMDoc::State_Searching: + + topColor = "#EBF1F6"; + midTopColor = "#ABD3EE"; + midBottomColor = "#89C3EB"; + bottomColor = "#D5EBFB"; //blue gloss #4 + //break; + + case CSMDoc::State_Verifying: + + topColor = "#BFD255"; + midTopColor = "#8EB92A"; + midBottomColor = "#72AA00"; + bottomColor = "#9ECB2D"; //green gloss + //break; + + case CSMDoc::State_Compiling: + + topColor = "#F3E2C7"; + midTopColor = "#C19E67"; + midBottomColor = "#B68D4C"; + bottomColor = "#E9D4B3"; //l Brown 3D + //break; + + default: + + topColor = "#F2F6F8"; + bottomColor = "#E0EFF9"; + midTopColor = "#D8E1E7"; + midBottomColor = "#B5C6D0"; // gray gloss for undefined ops + } + + setStyleSheet(style.arg(topColor).arg(midTopColor).arg(midBottomColor).arg(bottomColor)); +} diff --git a/apps/opencs/view/doc/operation.hpp b/apps/opencs/view/doc/operation.hpp index 362725b6f..a5abf73b7 100644 --- a/apps/opencs/view/doc/operation.hpp +++ b/apps/opencs/view/doc/operation.hpp @@ -25,7 +25,11 @@ namespace CSVDoc void setProgress (int current, int max, int threads); int getType() const; + + private: + + void setBarColor (int type); }; } -#endif \ No newline at end of file +#endif From aa2547151769a91b6a84704ab338b0bdee4ecac3 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 11 Feb 2013 15:01:00 +0100 Subject: [PATCH 601/916] WIP: working on improving the config file handling --- apps/launcher/CMakeLists.txt | 6 + apps/launcher/datafilespage.cpp | 295 +++++++++----------- apps/launcher/datafilespage.hpp | 14 +- apps/launcher/main.cpp | 34 ++- apps/launcher/maindialog.cpp | 79 ++++-- apps/launcher/maindialog.hpp | 16 +- apps/launcher/model/datafilesmodel.cpp | 4 +- apps/launcher/settings/gamesettings.cpp | 9 +- apps/launcher/settings/launchersettings.cpp | 45 +++ apps/launcher/settings/launchersettings.hpp | 16 ++ apps/launcher/settings/settingsbase.hpp | 23 +- apps/launcher/utils/lineedit.cpp | 13 +- apps/launcher/utils/lineedit.hpp | 2 +- apps/launcher/utils/profilescombobox.cpp | 65 ++++- apps/launcher/utils/profilescombobox.hpp | 4 +- 15 files changed, 404 insertions(+), 221 deletions(-) create mode 100644 apps/launcher/settings/launchersettings.cpp create mode 100644 apps/launcher/settings/launchersettings.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 044a0a0b7..3c721e238 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -11,7 +11,9 @@ set(LAUNCHER settings/gamesettings.cpp settings/graphicssettings.cpp + settings/launchersettings.cpp + utils/comboboxlineedit.cpp utils/naturalsort.cpp utils/lineedit.cpp utils/profilescombobox.cpp @@ -32,8 +34,10 @@ set(LAUNCHER_HEADER settings/gamesettings.hpp settings/graphicssettings.hpp + settings/launchersettings.hpp settings/settingsbase.hpp + utils/comboboxlineedit.cpp utils/lineedit.hpp utils/naturalsort.hpp utils/profilescombobox.hpp @@ -52,6 +56,7 @@ set(LAUNCHER_HEADER_MOC model/modelitem.hpp model/esm/esmfile.hpp + utils/comboboxlineedit.hpp utils/lineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp @@ -86,6 +91,7 @@ ENDIF(OGRE_STATIC) add_executable(omwlauncher ${GUI_TYPE} ${LAUNCHER} + ${LAUNCHER_HEADER} ${RCC_SRCS} ${MOC_SRCS} ) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index e25300394..12323b1f1 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -7,6 +7,7 @@ #include "model/esm/esmfile.hpp" #include "settings/gamesettings.hpp" +#include "settings/launchersettings.hpp" #include "utils/profilescombobox.hpp" #include "utils/lineedit.hpp" @@ -47,9 +48,10 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) return index1.row() <= index2.row(); } -DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, QWidget *parent) +DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent) : mCfgMgr(cfg) , mGameSettings(gameSettings) + , mLauncherSettings(launcherSettings) , QWidget(parent) { // Models @@ -129,15 +131,19 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mPluginsTable->setColumnHidden(8, true); // Add both tables to a splitter - QSplitter *splitter = new QSplitter(this); - splitter->setOrientation(Qt::Horizontal); - splitter->addWidget(mMastersTable); - splitter->addWidget(mPluginsTable); + mSplitter = new QSplitter(this); + mSplitter->setOrientation(Qt::Horizontal); + mSplitter->setChildrenCollapsible(false); // Don't allow the widgets to be hidden + mSplitter->addWidget(mMastersTable); + mSplitter->addWidget(mPluginsTable); // Adjust the default widget widths inside the splitter QList sizeList; - sizeList << 175 << 200; - splitter->setSizes(sizeList); + sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt(); + sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt(); + qDebug() << sizeList; + + mSplitter->setSizes(sizeList); // Bottom part with profile options QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); @@ -158,7 +164,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam QVBoxLayout *pageLayout = new QVBoxLayout(this); pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(splitter); + pageLayout->addWidget(mSplitter); pageLayout->addWidget(mProfileToolBar); // Create a dialog for the new profile name input @@ -178,8 +184,9 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); + connect(mSplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); + createActions(); - setupConfig(); setupDataFiles(); } @@ -221,126 +228,50 @@ void DataFilesPage::createActions() } -void DataFilesPage::setupConfig() -{ - // Open our config file - QString config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); - mLauncherConfig = new QSettings(config, QSettings::IniFormat); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - QStringList profiles = mLauncherConfig->childGroups(); - - // Add the profiles to the combobox - foreach (const QString &profile, profiles) { - - if (profile.contains(QRegExp("[^a-zA-Z0-9_]"))) - continue; // Profile name contains garbage - - - qDebug() << "adding " << profile; - mProfilesComboBox->addItem(profile); - } - - // Add a default profile - if (mProfilesComboBox->findText(QString("Default")) == -1) { - mProfilesComboBox->addItem(QString("Default")); - } - - QString currentProfile = mLauncherConfig->value("CurrentProfile").toString(); - - if (currentProfile.isEmpty()) { - // No current profile selected - currentProfile = "Default"; - } - - const int currentIndex = mProfilesComboBox->findText(currentProfile); - if (currentIndex != -1) { - // Profile is found - mProfilesComboBox->setCurrentIndex(currentIndex); - } - - mLauncherConfig->endGroup(); -} - - void DataFilesPage::readConfig() { - // Don't read the config if no masters are found - if (mMastersModel->rowCount() < 1) - return; +// // Don't read the config if no masters are found +// if (mMastersModel->rowCount() < 1) +// return; - QString profile = mProfilesComboBox->currentText(); - - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - mLauncherConfig->beginGroup(profile); - - QStringList childKeys = mLauncherConfig->childKeys(); - QStringList plugins; - - // Sort the child keys numerical instead of alphabetically - // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 - qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); - - foreach (const QString &key, childKeys) { - const QString keyValue = mLauncherConfig->value(key).toString(); - - if (key.startsWith("Plugin")) { - //QStringList checked = mPluginsModel->checkedItems(); - EsmFile *file = mPluginsModel->findItem(keyValue); - QModelIndex index = mPluginsModel->indexFromItem(file); - - mPluginsModel->setCheckState(index, Qt::Checked); - // Move the row to the top of te view - //mPluginsModel->moveRow(index.row(), checked.count()); - plugins << keyValue; - } - - if (key.startsWith("Master")) { - EsmFile *file = mMastersModel->findItem(keyValue); - mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); - } - } - - qDebug() << plugins; - - -// // Set the checked item positions -// const QStringList checked = mPluginsModel->checkedItems(); -// for (int i = 0; i < plugins.size(); ++i) { -// EsmFile *file = mPluginsModel->findItem(plugins.at(i)); -// QModelIndex index = mPluginsModel->indexFromItem(file); -// mPluginsModel->moveRow(index.row(), i); -// qDebug() << "Moving: " << plugins.at(i) << " from: " << index.row() << " to: " << i << " count: " << checked.count(); +// QString profile = mProfilesComboBox->currentText(); +// // Make sure we have no groups open +// while (!mLauncherConfig->group().isEmpty()) { +// mLauncherConfig->endGroup(); // } - // Iterate over the plugins to set their checkstate and position -// for (int i = 0; i < plugins.size(); ++i) { -// const QString plugin = plugins.at(i); +// mLauncherConfig->beginGroup("Profiles"); +// mLauncherConfig->beginGroup(profile); -// const QList pluginList = mPluginsModel->findItems(plugin); +// QStringList childKeys = mLauncherConfig->childKeys(); +// QStringList plugins; -// if (!pluginList.isEmpty()) -// { -// foreach (const QStandardItem *currentPlugin, pluginList) { -// mPluginsModel->setData(currentPlugin->index(), Qt::Checked, Qt::CheckStateRole); +// // Sort the child keys numerical instead of alphabetically +// // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 +// qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); -// // Move the plugin to the position specified in the config file -// mPluginsModel->insertRow(i, mPluginsModel->takeRow(currentPlugin->row())); -// } +// foreach (const QString &key, childKeys) { +// const QString keyValue = mLauncherConfig->value(key).toString(); + +// if (key.startsWith("Plugin")) { +// //QStringList checked = mPluginsModel->checkedItems(); +// EsmFile *file = mPluginsModel->findItem(keyValue); +// QModelIndex index = mPluginsModel->indexFromItem(file); + +// mPluginsModel->setCheckState(index, Qt::Checked); +// // Move the row to the top of te view +// //mPluginsModel->moveRow(index.row(), checked.count()); +// plugins << keyValue; +// } + +// if (key.startsWith("Master")) { +// EsmFile *file = mMastersModel->findItem(keyValue); +// mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); // } // } +// qDebug() << plugins; } void DataFilesPage::setupDataFiles() @@ -362,10 +293,43 @@ void DataFilesPage::setupDataFiles() mPluginsModel->addPlugins(dataLocal); } + loadSettings(); +} + +void DataFilesPage::loadSettings() +{ + qDebug() << "load settings"; +} + +void DataFilesPage::saveSettings() +{ + QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + qDebug() << "save settings" << profile; + + QStringList items = mMastersModel->checkedItems(); + + foreach(const QString &master, items) { + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), master); + } + + items.clear(); + items = mPluginsModel->checkedItems(); + + qDebug() << items.size(); + + foreach(const QString &plugin, items) { + qDebug() << "setting " << plugin; + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), plugin); + } + + + } void DataFilesPage::writeConfig(QString profile) { + + // // Don't overwrite the config if no masters are found // if (mMastersModel->rowCount() < 1) // return; @@ -518,21 +482,22 @@ void DataFilesPage::writeConfig(QString profile) void DataFilesPage::newProfile() { - if (mNewProfileDialog->exec() == QDialog::Accepted) { +// if (mNewProfileDialog->exec() == QDialog::Accepted) { - const QString text = mNewProfileDialog->lineEdit()->text(); - mProfilesComboBox->addItem(text); +// const QString text = mNewProfileDialog->lineEdit()->text(); +// mProfilesComboBox->addItem(text); +// mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); +// } - // Copy the currently checked items to cfg - writeConfig(text); - mLauncherConfig->sync(); - - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); - } + mDeleteProfileAction->setEnabled(false); + mProfilesComboBox->setCurrentIndex(-1); + mProfilesComboBox->setEditEnabled(true); + mProfilesComboBox->lineEdit()->setFocus(); } void DataFilesPage::updateOkButton(const QString &text) { + // We do this here because we need the profiles combobox text if (text.isEmpty()) { mNewProfileDialog->setOkButtonEnabled(false); return; @@ -543,6 +508,16 @@ void DataFilesPage::updateOkButton(const QString &text) : mNewProfileDialog->setOkButtonEnabled(false); } +void DataFilesPage::updateSplitter() +{ + // Sigh, update the saved splitter size in settings only when moved + // Since getting mSplitter->sizes() if page is hidden returns invalid values + QList sizes = mSplitter->sizes(); + + mLauncherSettings.setValue(QString("General/MastersTable/width"), QString::number(sizes.at(0))); + mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1))); +} + void DataFilesPage::deleteProfile() { QString profile = mProfilesComboBox->currentText(); @@ -562,18 +537,8 @@ void DataFilesPage::deleteProfile() msgBox.exec(); if (msgBox.clickedButton() == deleteButton) { - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } - - mLauncherConfig->beginGroup("Profiles"); - - // Open the profile-name subgroup - mLauncherConfig->beginGroup(profile); - mLauncherConfig->remove(""); // Clear the subgroup - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); // Remove the profile from the combobox mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); @@ -624,11 +589,8 @@ void DataFilesPage::refresh() { mPluginsModel->sort(0); - // Refresh the plugins table mPluginsTable->scrollToTop(); - writeConfig(); - readConfig(); } @@ -679,50 +641,43 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre mProfilesComboBox->setEditEnabled(true); } - if (!previous.isEmpty()) { - writeConfig(previous); - mLauncherConfig->sync(); - - if (mProfilesComboBox->currentIndex() == -1) - return; - - } else { + if (previous.isEmpty()) return; - } + + if (mProfilesComboBox->findText(previous) == -1) + return; // Profile was deleted + + // Store the previous profile + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), previous); + saveSettings(); + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); + mMastersModel->uncheckAll(); mPluginsModel->uncheckAll(); - readConfig(); + loadSettings(); } void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) { + qDebug() << "rename"; if (previous.isEmpty()) return; // Save the new profile name - writeConfig(current); + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); + saveSettings(); - // Make sure we have no groups open - while (!mLauncherConfig->group().isEmpty()) { - mLauncherConfig->endGroup(); - } + // Remove the old one + mLauncherSettings.remove(QString("Profiles/") + previous + QString("/master")); + mLauncherSettings.remove(QString("Profiles/") + previous + QString("/plugin")); - mLauncherConfig->beginGroup("Profiles"); + // Remove the profile from the combobox + mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - // Open the profile-name subgroup - mLauncherConfig->beginGroup(previous); - mLauncherConfig->remove(""); // Clear the subgroup - mLauncherConfig->endGroup(); - mLauncherConfig->endGroup(); - mLauncherConfig->sync(); - - // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); - readConfig(); + mMastersModel->uncheckAll(); + mPluginsModel->uncheckAll(); + loadSettings(); } void DataFilesPage::showContextMenu(const QPoint &point) diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index e40d29d60..2dbbdb667 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -6,16 +6,18 @@ class QTableView; class QSortFilterProxyModel; -class QSettings; class QAction; class QToolBar; +class QSplitter; class QMenu; + class ProfilesComboBox; class DataFilesModel; class TextInputDialog; class ProfilesComboBox; class GameSettings; +class LauncherSettings; namespace Files { struct ConfigurationManager; } @@ -24,11 +26,13 @@ class DataFilesPage : public QWidget Q_OBJECT public: - DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, QWidget *parent = 0); + DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0); ProfilesComboBox *mProfilesComboBox; void writeConfig(QString profile = QString()); + void saveSettings(); + public slots: void setCheckState(QModelIndex index); @@ -38,6 +42,7 @@ public slots: void profileChanged(const QString &previous, const QString ¤t); void profileRenamed(const QString &previous, const QString ¤t); void updateOkButton(const QString &text); + void updateSplitter(); // Action slots void newProfile(); @@ -61,6 +66,7 @@ private: QToolBar *mProfileToolBar; QMenu *mContextMenu; + QSplitter *mSplitter; QAction *mNewProfileAction; QAction *mDeleteProfileAction; @@ -74,8 +80,8 @@ private: Files::ConfigurationManager &mCfgMgr; - QSettings *mLauncherConfig; GameSettings &mGameSettings; + LauncherSettings &mLauncherSettings; TextInputDialog *mNewProfileDialog; @@ -87,6 +93,8 @@ private: void setupConfig(); void readConfig(); + void loadSettings(); + }; #endif diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 43bf50fbc..ba84518c1 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -16,6 +16,7 @@ #include "maindialog.hpp" #include "settings/gamesettings.hpp" #include "settings/graphicssettings.hpp" +#include "settings/launchersettings.hpp" int main(int argc, char *argv[]) @@ -52,6 +53,7 @@ int main(int argc, char *argv[]) GameSettings gameSettings(cfgMgr); GraphicsSettings graphicsSettings; + LauncherSettings launcherSettings; QStringList paths; paths.append(userPath + QString("openmw.cfg")); @@ -118,8 +120,6 @@ int main(int argc, char *argv[]) } // On to the graphics settings - qDebug() << userPath; - QFile localDefault(QString("settings-default.cfg")); QFile globalDefault(globalPath + QString("settings-default.cfg")); @@ -163,8 +163,36 @@ int main(int argc, char *argv[]) file.close(); } + // Now the launcher settings + paths.clear(); + paths.append(QString("launcher.cfg")); + paths.append(userPath + QString("launcher.cfg")); - MainDialog mainWin(gameSettings, graphicsSettings); + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error opening OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return 0; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + launcherSettings.readFile(stream); + } + file.close(); + } + + + MainDialog mainWin(gameSettings, graphicsSettings, launcherSettings); if (mainWin.setup()) { mainWin.show(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 4d3d24bd9..f48ea603b 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -2,6 +2,7 @@ #include "settings/gamesettings.hpp" #include "settings/graphicssettings.hpp" +#include "settings/launchersettings.hpp" #include "utils/profilescombobox.hpp" @@ -11,9 +12,11 @@ #include "datafilespage.hpp" MainDialog::MainDialog(GameSettings &gameSettings, - GraphicsSettings &graphicsSettings) + GraphicsSettings &graphicsSettings, + LauncherSettings &launcherSettings) : mGameSettings(gameSettings) , mGraphicsSettings(graphicsSettings) + , mLauncherSettings(launcherSettings) { QWidget *centralWidget = new QWidget(this); @@ -132,7 +135,7 @@ void MainDialog::createPages() { mPlayPage = new PlayPage(this); mGraphicsPage = new GraphicsPage(mCfgMgr, mGraphicsSettings, this); - mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, this); + mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); @@ -161,18 +164,11 @@ void MainDialog::createPages() bool MainDialog::setup() { - // Setup the Graphics page + // Call this so we can exit on Ogre errors before mainwindow is shown if (!mGraphicsPage->setupOgre()) { return false; } - // Setup the Data Files page - /* - if (!mDataFilesPage->setupDataFiles()) { - return false; - }*/ - - return true; } @@ -184,11 +180,28 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) mPagesWidget->setCurrentIndex(mIconWidget->row(current)); } -void MainDialog::closeEvent(QCloseEvent *event) +void MainDialog::loadSettings() +{ + +} + +void MainDialog::saveSettings() +{ + QString width = QString::number(this->width()); + QString height = QString::number(this->height()); + + mLauncherSettings.setValue(QString("General/MainWindow/width"), width); + mLauncherSettings.setValue(QString("General/MainWindow/height"), height); + + qDebug() << "size: " << width << height; +} + +void MainDialog::writeSettings() { // Now write all config files - mDataFilesPage->writeConfig(); + saveSettings(); mGraphicsPage->saveSettings(); + mDataFilesPage->saveSettings(); QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QDir dir(userPath); @@ -203,7 +216,7 @@ void MainDialog::closeEvent(QCloseEvent *event) Please make sure you have the right permissions \ and try again.
").arg(userPath)); msgBox.exec(); - event->accept(); + return; } } @@ -220,7 +233,7 @@ void MainDialog::closeEvent(QCloseEvent *event) Please make sure you have the right permissions \ and try again.
").arg(file.fileName())); msgBox.exec(); - event->accept(); + return; } QTextStream stream(&file); @@ -242,26 +255,52 @@ void MainDialog::closeEvent(QCloseEvent *event) Please make sure you have the right permissions \ and try again.
").arg(file.fileName())); msgBox.exec(); - event->accept(); + return; } stream.setDevice(&file); stream.setCodec(QTextCodec::codecForName("UTF-8")); mGraphicsSettings.writeFile(stream); + file.close(); + // Launcher settings + file.setFileName(userPath + QString("launcher.cfg")); + + if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle("Error writing Launcher configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0 for writing

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return; + } + + stream.setDevice(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mLauncherSettings.writeFile(stream); + file.close(); +} + +void MainDialog::closeEvent(QCloseEvent *event) +{ + saveSettings(); + writeSettings(); event->accept(); } void MainDialog::play() { // First do a write of all the configs, just to be sure - mDataFilesPage->writeConfig(); + //mDataFilesPage->writeConfig(); //mGraphicsPage->writeConfig(); - - // Save user settings - const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); - mSettings.saveUser(settingspath); + saveSettings(); + writeSettings(); #ifdef Q_OS_WIN QString game = "./openmw.exe"; diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index c9654b874..7167d101d 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -4,7 +4,6 @@ #include #include -#include class QListWidget; class QListWidgetItem; @@ -19,22 +18,31 @@ class DataFilesPage; class GameSettings; class GraphicsSettings; +class LauncherSettings; class MainDialog : public QMainWindow { Q_OBJECT public: - MainDialog(GameSettings &gameSettings, GraphicsSettings &GraphicsSettings); + MainDialog(GameSettings &gameSettings, + GraphicsSettings &GraphicsSettings, + LauncherSettings &launcherSettings); + + bool setup(); public slots: void changePage(QListWidgetItem *current, QListWidgetItem *previous); void play(); - bool setup(); private: void createIcons(); void createPages(); + + void loadSettings(); + void saveSettings(); + void writeSettings(); + void closeEvent(QCloseEvent *event); QListWidget *mIconWidget; @@ -45,10 +53,10 @@ private: DataFilesPage *mDataFilesPage; Files::ConfigurationManager mCfgMgr; - Settings::Manager mSettings; GameSettings &mGameSettings; GraphicsSettings &mGraphicsSettings; + LauncherSettings &mLauncherSettings; }; diff --git a/apps/launcher/model/datafilesmodel.cpp b/apps/launcher/model/datafilesmodel.cpp index e84dbe0ac..ae59cc3c3 100644 --- a/apps/launcher/model/datafilesmodel.cpp +++ b/apps/launcher/model/datafilesmodel.cpp @@ -334,6 +334,7 @@ void DataFilesModel::addPlugins(const QString &path) QFileInfo info(dir.absoluteFilePath(path)); EsmFile *file = new EsmFile(path); + try { ESM::ESMReader fileReader; ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(mEncoding.toStdString())); @@ -361,7 +362,8 @@ void DataFilesModel::addPlugins(const QString &path) // Put the file in the table - addFile(file); + if (findItem(path) == 0) + addFile(file); } catch(std::runtime_error &e) { // An error occurred while reading the .esp qWarning() << "Error reading esp: " << e.what(); diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 2420c1e6c..5f0fb77bc 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -101,7 +101,14 @@ bool GameSettings::readFile(QTextStream &stream) qDebug() << "key: " << key; // There can be multiple data keys if (key == QLatin1String("data")) { - cache.insertMulti(key, value); + // Remove keys from previous config and overwrite them + mSettings.remove(key); + QStringList values = cache.values(key); + if (!values.contains(value)) { + // Do not insert duplicate values + qDebug() << "values does not contain: " << value << values; + cache.insertMulti(key, value); + } } else { cache.insert(key, value); } diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp new file mode 100644 index 000000000..c189c282f --- /dev/null +++ b/apps/launcher/settings/launchersettings.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include "launchersettings.hpp" + +LauncherSettings::LauncherSettings() +{ +} + +LauncherSettings::~LauncherSettings() +{ +} + + +bool LauncherSettings::writeFile(QTextStream &stream) +{ + QString sectionPrefix; + QRegExp sectionRe("([^/]+)/(.+)$"); + QMap settings = SettingsBase::getSettings(); + + QMapIterator i(settings); + while (i.hasNext()) { + i.next(); + + QString prefix; + QString key; + + if (sectionRe.exactMatch(i.key())) { + prefix = sectionRe.cap(1); + key = sectionRe.cap(2); + } + + if (sectionPrefix != prefix) { + sectionPrefix = prefix; + stream << "\n[" << prefix << "]\n"; + } + + stream << key << "=" << i.value() << "\n"; + } + + return true; + +} diff --git a/apps/launcher/settings/launchersettings.hpp b/apps/launcher/settings/launchersettings.hpp new file mode 100644 index 000000000..cf4dd4c9f --- /dev/null +++ b/apps/launcher/settings/launchersettings.hpp @@ -0,0 +1,16 @@ +#ifndef LAUNCHERSETTINGS_HPP +#define LAUNCHERSETTINGS_HPP + +#include "settingsbase.hpp" + +class LauncherSettings : public SettingsBase> +{ +public: + LauncherSettings(); + ~LauncherSettings(); + + bool writeFile(QTextStream &stream); + +}; + +#endif // LAUNCHERSETTINGS_HPP diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 6b8b52762..e09ea6203 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -2,6 +2,7 @@ #define SETTINGSBASE_HPP #include +#include #include #include #include @@ -26,6 +27,17 @@ public: mSettings.insert(key, value); } + inline void setMultiValue(const QString &key, const QString &value) + { + mSettings.insertMulti(key, value); + } + + + inline void remove(const QString &key) + { + mSettings.remove(key); + } + Map getSettings() {return mSettings;} bool readFile(QTextStream &stream) @@ -56,11 +68,18 @@ public: if (!sectionPrefix.isEmpty()) key.prepend(sectionPrefix); - // QMap will replace the value if key exists, QMultiMap creates a new one - mCache.insert(key, value); + mSettings.remove(key); + + QStringList values = mCache.values(key); + if (!values.contains(value)) { + // QMap will replace the value if key exists, QMultiMap creates a new one + mCache.insert(key, value); + } } } + qDebug() << "HI THERE! " << mCache; + if (mSettings.isEmpty()) { mSettings = mCache; // This is the first time we read a file return true; diff --git a/apps/launcher/utils/lineedit.cpp b/apps/launcher/utils/lineedit.cpp index dac196425..b0f339589 100644 --- a/apps/launcher/utils/lineedit.cpp +++ b/apps/launcher/utils/lineedit.cpp @@ -1,7 +1,8 @@ -#include "lineedit.hpp" #include #include +#include "lineedit.hpp" + LineEdit::LineEdit(QWidget *parent) : QLineEdit(parent) { @@ -13,9 +14,11 @@ LineEdit::LineEdit(QWidget *parent) mClearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }"); mClearButton->hide(); connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear())); - connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateCloseButton(const QString&))); + connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateClearButton(const QString&))); int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); - setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1)); + + setObjectName(QString("LineEdit")); + setStyleSheet(QString("LineEdit { padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1)); QSize msz = minimumSizeHint(); setMinimumSize(qMax(msz.width(), mClearButton->sizeHint().height() + frameWidth * 2 + 2), qMax(msz.height(), mClearButton->sizeHint().height() + frameWidth * 2 + 2)); @@ -29,9 +32,7 @@ void LineEdit::resizeEvent(QResizeEvent *) (rect().bottom() + 1 - sz.height())/2); } -void LineEdit::updateCloseButton(const QString& text) +void LineEdit::updateClearButton(const QString& text) { mClearButton->setVisible(!text.isEmpty()); } - - diff --git a/apps/launcher/utils/lineedit.hpp b/apps/launcher/utils/lineedit.hpp index 2ed76d6eb..14bd7b1b4 100644 --- a/apps/launcher/utils/lineedit.hpp +++ b/apps/launcher/utils/lineedit.hpp @@ -25,7 +25,7 @@ protected: void resizeEvent(QResizeEvent *); private slots: - void updateCloseButton(const QString &text); + void updateClearButton(const QString &text); private: QToolButton *mClearButton; diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp index 8354d4a78..3a75ba417 100644 --- a/apps/launcher/utils/profilescombobox.cpp +++ b/apps/launcher/utils/profilescombobox.cpp @@ -1,45 +1,94 @@ #include #include #include +#include +#include #include "profilescombobox.hpp" +#include "comboboxlineedit.hpp" ProfilesComboBox::ProfilesComboBox(QWidget *parent) : QComboBox(parent) { mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore - - setEditable(true); + setEditEnabled(true); setValidator(mValidator); setCompleter(0); connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotIndexChanged(int))); - connect(lineEdit(), SIGNAL(returnPressed()), this, - SLOT(slotReturnPressed())); + + } void ProfilesComboBox::setEditEnabled(bool editable) { - if (!editable) + qDebug() << "called"; + if (isEditable() == editable) + return; + + if (!editable) { + disconnect(lineEdit(), SIGNAL(editingFinished()), this, SLOT(slotEditingFinished())); + disconnect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotTextChanged(QString))); return setEditable(false); + } // Reset the completer and validator setEditable(true); setValidator(mValidator); + + ComboBoxLineEdit *edit = new ComboBoxLineEdit(this); + setLineEdit(edit); setCompleter(0); + + connect(lineEdit(), SIGNAL(editingFinished()), this, + SLOT(slotEditingFinished())); + + connect(lineEdit(), SIGNAL(textChanged(QString)), this, + SLOT(slotTextChanged(QString))); } -void ProfilesComboBox::slotReturnPressed() +void ProfilesComboBox::slotTextChanged(const QString &text) { + QString previous = itemText(currentIndex()); +// lineEdit()->setPalette(QApplication::palette()); + + if (text.isEmpty()) + return; + + if (text == previous) + return; + + qDebug() << "textChanged"; + if (findText(text) != -1) { + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Text,Qt::red); + lineEdit()->setPalette(*palette); + } +} + +void ProfilesComboBox::slotEditingFinished() +{ + qDebug() << "returnpressed"; QString current = currentText(); QString previous = itemText(currentIndex()); + if (current.isEmpty()) + return; + + if (current == previous) + return; + if (findText(current) != -1) return; - setItemText(currentIndex(), current); - emit(profileRenamed(previous, current)); + + if (currentIndex() == -1) { + addItem(currentText()); + } else { + setItemText(currentIndex(), current); + emit(profileRenamed(previous, current)); + } } void ProfilesComboBox::slotIndexChanged(int index) diff --git a/apps/launcher/utils/profilescombobox.hpp b/apps/launcher/utils/profilescombobox.hpp index c7da60d2a..08ead9a7a 100644 --- a/apps/launcher/utils/profilescombobox.hpp +++ b/apps/launcher/utils/profilescombobox.hpp @@ -4,7 +4,6 @@ #include class QString; - class QRegExpValidator; class ProfilesComboBox : public QComboBox @@ -19,8 +18,9 @@ signals: void profileRenamed(const QString &oldName, const QString &newName); private slots: - void slotReturnPressed(); + void slotEditingFinished(); void slotIndexChanged(int index); + void slotTextChanged(const QString &text); private: QString mOldProfile; From ba97c8f7d675067b389bbb3e8a127cc67038a7f6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Feb 2013 19:54:32 +0100 Subject: [PATCH 602/916] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 5d486c74e..936f3efd9 100644 --- a/credits.txt +++ b/credits.txt @@ -26,6 +26,7 @@ gugus / gus Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) +Joel Graff (graffy) Karl-Felix Glatzer (k1ll) lazydev Leon Saunders (emoose) From 3b64389668d181754ec08fc2f4c010bc5a9d3b98 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Tue, 12 Feb 2013 11:14:30 +0400 Subject: [PATCH 603/916] BookTextParser: fixed infinitive loop --- apps/openmw/mwgui/formatting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 4090b592d..1689d2fb1 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -160,7 +160,7 @@ std::vector BookTextParser::split(std::string text, const int width ++i; } - if (currentHeight > height-spacing) + if (currentHeight > height-spacing && currentText.size() != currentWord.size()) { // remove the last word currentText.erase(currentText.size()-currentWord.size(), currentText.size()); From 03803f19b5ded40a476181189027d3b5fc706ba1 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Tue, 12 Feb 2013 11:22:19 +0400 Subject: [PATCH 604/916] BookTextParser: moved to Ogre::UTFString Font height and unicode characters glyph width now accounted correctly. --- apps/openmw/mwgui/formatting.cpp | 168 +++++++++++++++++-------------- apps/openmw/mwgui/formatting.hpp | 2 + 2 files changed, 96 insertions(+), 74 deletions(-) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 1689d2fb1..c50381a87 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -6,7 +6,9 @@ #include "../mwworld/ptr.hpp" #include +#include #include +#include using namespace MWGui; @@ -67,118 +69,134 @@ namespace return value; } + + Ogre::UTFString::unicode_char unicodeCharFromChar(char ch) + { + std::string s; + s += ch; + Ogre::UTFString string(s); + return string.getChar(0); + } } -std::vector BookTextParser::split(std::string text, const int width, const int height) +std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) { + using Ogre::UTFString; std::vector result; MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - text = Interpreter::fixDefinesBook(text, interpreterContext); + utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); - boost::algorithm::replace_all(text, "
", "\n"); - boost::algorithm::replace_all(text, "

", "\n\n"); + boost::algorithm::replace_all(utf8Text, "
", "\n"); + boost::algorithm::replace_all(utf8Text, "

", "\n\n"); + UTFString text(utf8Text); const int spacing = 48; - while (text.size() > 0) + const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); + const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); + const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); + + while (!text.empty()) { // read in characters until we have exceeded the size, or run out of text int currentWidth = 0; int currentHeight = 0; - std::string currentText; - std::string currentWord; - unsigned int i=0; - while (currentHeight <= height-spacing && i', i) == std::string::npos) + const size_t tagStart = index + 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == UTFString::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); - if (text.size() > i+4 && text.substr(i, 4) == "', i)-i), false); - currentHeight += (mHeight-h); + const int h = mHeight; + parseImage(tag, false); + currentHeight += (mHeight - h); currentWidth = 0; } - else if (text.size() > i+5 && text.substr(i, 5) == "', i)-i)); - currentHeight += 18; // keep this in sync with the font size + parseFont(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } currentWidth = 0; } - else if (text.size() > i+4 && text.substr(i, 4) == "', i)-i)); - currentHeight += 18; // keep this in sync with the font size - currentWidth = 0; + parseDiv(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } } - - currentText += text.substr(i, text.find('>', i)-i+1); - i = text.find('>', i); + index = tagEnd; } - else if (text[i] == '\n') + else if (ch == NEWLINE) { - currentHeight += 18; // keep this in sync with the font size + currentHeight += currentFontHeight(); currentWidth = 0; - currentWord = ""; - currentText += text[i]; + currentWordStart = index; } - else if (text[i] == ' ') + else if (ch == SPACE) { currentWidth += 3; // keep this in sync with the font's SpaceWidth property - currentWord = ""; - currentText += text[i]; + currentWordStart = index; } else { - currentWidth += - MyGUI::FontManager::getInstance().getByName (mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont) - ->getGlyphInfo(static_cast(text[i]))->width; - currentWord += text[i]; - currentText += text[i]; + currentWidth += widthForCharGlyph(ch); } if (currentWidth > width) { - currentHeight += 18; // keep this in sync with the font size + currentHeight += currentFontHeight(); currentWidth = 0; - // add size of the current word - unsigned int j=0; - while (jgetGlyphInfo(static_cast(currentWord[j]))->width; - ++j; - } + UTFString word = text.substr(currentWordStart, index - currentWordStart); + for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) + currentWidth += widthForCharGlyph(it.getCharacter()); } - - ++i; - } - if (currentHeight > height-spacing && currentText.size() != currentWord.size()) - { - // remove the last word - currentText.erase(currentText.size()-currentWord.size(), currentText.size()); + index += UTFString::_utf16_char_length(ch); } + const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) + ? currentWordStart : index; - result.push_back(currentText); - text.erase(0, currentText.size()); + result.push_back(text.substr(0, pageEnd).asUTF8()); + text.erase(0, pageEnd); } return result; } +float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const +{ + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName) + ->getGlyphInfo(unicodeChar)->width; +} + +float BookTextParser::currentFontHeight() const +{ + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); +} + MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor text = Interpreter::fixDefinesBook(text, interpreterContext); - mParent = parent; mWidth = width; mHeight = 0; @@ -193,8 +211,8 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co boost::algorithm::replace_all(text, "

", "\n\n"); // remove leading newlines - //while (text[0] == '\n') - // text.erase(0); +// while (text[0] == '\n') +// text.erase(0); // remove trailing " if (text[text.size()-1] == '\"') @@ -279,28 +297,30 @@ void BookTextParser::parseSubText(std::string text) { if (text[0] == '<') { - if (text.find('>') == std::string::npos) + const size_t tagStart = 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == std::string::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart); - if (text.size() > 4 && text.substr(0, 4) == "'))); - else if (text.size() > 5 && text.substr(0, 5) == "'))); - else if (text.size() > 4 && text.substr(0, 4) == "'))); + if (boost::algorithm::starts_with(tag, "IMG")) + parseImage(tag); + if (boost::algorithm::starts_with(tag, "FONT")) + parseFont(tag); + if (boost::algorithm::starts_with(tag, "DOV")) + parseDiv(tag); - text.erase(0, text.find('>')+1); + text.erase(0, tagEnd + 1); } - bool tagFound = false; + size_t tagStart = std::string::npos; std::string realText; // real text, without tags - unsigned int i=0; - for (; isetSize(box->getSize().width, box->getTextSize().height); mHeight += box->getTextSize().height; - if (tagFound) + if (tagStart != std::string::npos) { - parseSubText(text.substr(i, text.size())); + parseSubText(text.substr(tagStart, text.size())); } } diff --git a/apps/openmw/mwgui/formatting.hpp b/apps/openmw/mwgui/formatting.hpp index a1e115491..ab1ee3af4 100644 --- a/apps/openmw/mwgui/formatting.hpp +++ b/apps/openmw/mwgui/formatting.hpp @@ -40,6 +40,8 @@ namespace MWGui std::vector split(std::string text, const int width, const int height); protected: + float widthForCharGlyph(unsigned unicodeChar) const; + float currentFontHeight() const; void parseSubText(std::string text); void parseImage(std::string tag, bool createWidget=true); From 7d7a1119daccbf4a342555a3395c00fbd5e9f817 Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Tue, 12 Feb 2013 11:49:20 +0400 Subject: [PATCH 605/916] Fixed book text misalignment, at least in some cases https://bugs.openmw.org/issues/284 --- apps/openmw/mwgui/formatting.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index c50381a87..7f28e9e17 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -87,6 +87,7 @@ std::vector BookTextParser::split(std::string utf8Text, const int w MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); + boost::algorithm::replace_all(utf8Text, "\n", ""); boost::algorithm::replace_all(utf8Text, "
", "\n"); boost::algorithm::replace_all(utf8Text, "

", "\n\n"); @@ -207,6 +208,7 @@ MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, co MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); } + boost::algorithm::replace_all(text, "\n", ""); boost::algorithm::replace_all(text, "
", "\n"); boost::algorithm::replace_all(text, "

", "\n\n"); From f9a0a19ee1303ac3242695fcdf329169d6410523 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 12 Feb 2013 13:23:25 +0100 Subject: [PATCH 606/916] Fix a small issue in the windows installer, also added the OpenMW version to the installed package name --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 577b6f6b2..cfd1c7dd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -391,11 +391,11 @@ if(WIN32) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") SET(CPACK_GENERATOR "NSIS") - SET(CPACK_PACKAGE_NAME "OpenMW") + SET(CPACK_PACKAGE_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_PACKAGE_VENDOR "OpenMW.org") SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) - SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO}) + SET(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW;omwlauncher;OpenMW Launcher") SET(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Readme.lnk' '\$INSTDIR\\\\readme.txt'") From 0ae01794f1e1b106bf7fbfe592aade099036a285 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 12 Feb 2013 13:57:16 +0100 Subject: [PATCH 607/916] Fixed build errors in OpenCS --- apps/opencs/model/world/record.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 229985a8a..14f63c155 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -3,19 +3,19 @@ CSMWorld::RecordBase::~RecordBase() {} -bool CSMWorld::RecordBase::RecordBase::isDeleted() const +bool CSMWorld::RecordBase::isDeleted() const { return mState==State_Deleted || mState==State_Erased; } -bool CSMWorld::RecordBase::RecordBase::isErased() const +bool CSMWorld::RecordBase::isErased() const { return mState==State_Erased; } -bool CSMWorld::RecordBase::RecordBase::isModified() const +bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; } \ No newline at end of file From bbb845824d90a87661df67366f8e8129b68d25e2 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 12 Feb 2013 13:59:24 +0100 Subject: [PATCH 608/916] Added typedef for ssize_t in windows and fixed a use of __PRETTY_FUNCTION__ --- apps/openmw/mwrender/videoplayer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index baec2f740..b71022504 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -17,6 +17,11 @@ #include "../mwsound/sound_decoder.hpp" #include "../mwsound/sound.hpp" +#ifdef _WIN32 +#include + +typedef SSIZE_T ssize_t; +#endif namespace MWRender { @@ -361,7 +366,11 @@ class MovieAudioDecoder : public MWSound::Sound_Decoder } void open(const std::string&) +#ifdef _WIN32 + { fail(std::string("Invalid call to ")+__FUNCSIG__); } +#else { fail(std::string("Invalid call to ")+__PRETTY_FUNCTION__); } +#endif void close() { } From d213ff680ff5e71874ef33065d38f1285d68e67a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Feb 2013 20:55:45 +0100 Subject: [PATCH 609/916] Disabled terrain LOD --- apps/openmw/mwrender/terrain.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 2c2e9e6fc..df8d34e74 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -40,9 +40,9 @@ namespace MWRender ->getActiveProfile(); mActiveProfile = static_cast(activeProfile); - //The pixel error should be as high as possible without it being noticed - //as it governs how fast mesh quality decreases. - mTerrainGlobals->setMaxPixelError(8); + // We don't want any pixel error at all. Really, LOD makes no sense here - morrowind uses 65x65 verts in one cell, + // so applying LOD is most certainly slower than doing no LOD at all. + mTerrainGlobals->setMaxPixelError(0); mTerrainGlobals->setLayerBlendMapSize(32); From de90b911c9d729fc4abe856fed525d565beb1c71 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Feb 2013 20:56:00 +0100 Subject: [PATCH 610/916] Near clip plane corrections --- apps/openmw/mwrender/refraction.cpp | 36 ++++++++++++++++++++++++++--- apps/openmw/mwrender/refraction.hpp | 11 ++++++++- apps/openmw/mwrender/water.cpp | 9 ++++++-- apps/openmw/mwrender/water.hpp | 1 + 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 85642bc08..05229da1d 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "renderconst.hpp" @@ -14,9 +15,13 @@ namespace MWRender Refraction::Refraction(Ogre::Camera *parentCamera) : mParentCamera(parentCamera) + , mRenderActive(false) + , mIsUnderwater(false) { mCamera = mParentCamera->getSceneManager()->createCamera("RefractionCamera"); + mParentCamera->getSceneManager()->addRenderQueueListener(this); + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("WaterRefraction", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); @@ -24,7 +29,7 @@ namespace MWRender Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); - vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain); + vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); vp->setMaterialScheme("water_reflection"); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); @@ -47,17 +52,42 @@ namespace MWRender mCamera->setAspectRatio(mParentCamera->getAspectRatio()); mCamera->setFOVy(mParentCamera->getFOVy()); - mCamera->enableCustomNearClipPlane(mNearClipPlane); + mRenderActive = true; } void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { - + mRenderActive = false; } void Refraction::setHeight(float height) { mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,1,0), -(height + 5)); + mNearClipPlaneUnderwater = Ogre::Plane( Ogre::Vector3(0,1,0), height - 5); + } + + void Refraction::setViewportBackground (Ogre::ColourValue colour) + { + mRenderTarget->getViewport (0)->setBackgroundColour (colour); + } + + void Refraction::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) + { + // We don't want the sky to get clipped by custom near clip plane (the water plane) + if (queueGroupId < 20 && mRenderActive) + { + mCamera->disableCustomNearClipPlane(); + Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + } + } + + void Refraction::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) + { + if (queueGroupId < 20 && mRenderActive) + { + mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); + Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + } } } diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp index e3777d9cf..6b3c487c1 100644 --- a/apps/openmw/mwrender/refraction.hpp +++ b/apps/openmw/mwrender/refraction.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace Ogre { @@ -13,7 +14,7 @@ namespace Ogre namespace MWRender { - class Refraction : public Ogre::RenderTargetListener + class Refraction : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener { public: @@ -23,12 +24,20 @@ namespace MWRender void setHeight (float height); void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + void setViewportBackground(Ogre::ColourValue colour); + void setUnderwater(bool underwater) {mIsUnderwater = underwater;} + + void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); + void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); private: Ogre::Camera* mParentCamera; Ogre::Camera* mCamera; Ogre::RenderTarget* mRenderTarget; Ogre::Plane mNearClipPlane; + Ogre::Plane mNearClipPlaneUnderwater; + bool mRenderActive; + bool mIsUnderwater; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 867829564..f31dca08c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -124,8 +124,8 @@ void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::St { if (queueGroupId < 20 && mRenderActive) { - if (!mIsUnderwater) - mCamera->enableCustomNearClipPlane(mErrorPlane); + // this trick does not seem to work well for extreme angles + mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); } } @@ -159,6 +159,7 @@ void PlaneReflection::setHeight (float height) { mWaterPlane = Plane(Ogre::Vector3(0,1,0), height); mErrorPlane = Plane(Ogre::Vector3(0,1,0), height - 5); + mErrorPlaneUnderwater = Plane(Ogre::Vector3(0,-1,0), -height - 5); } void PlaneReflection::setActive (bool active) @@ -348,6 +349,8 @@ Water::updateUnderwater(bool underwater) if (mReflection) mReflection->setUnderwater (mIsUnderwater); + if (mRefraction) + mRefraction->setUnderwater (mIsUnderwater); updateVisible(); } @@ -377,6 +380,8 @@ void Water::setViewportBackground(const ColourValue& bg) { if (mReflection) mReflection->setViewportBackground(bg); + if (mRefraction) + mRefraction->setViewportBackground(bg); } void Water::updateVisible() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index cf181674a..9aa18f008 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -89,6 +89,7 @@ namespace MWRender { SkyManager* mSky; Ogre::Plane mWaterPlane; Ogre::Plane mErrorPlane; + Ogre::Plane mErrorPlaneUnderwater; bool mRenderActive; }; From 5b2ca6fa7d3a6f61f6a5b60bb1cd1144ffd04a8f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Feb 2013 00:43:29 -0800 Subject: [PATCH 611/916] Don't complain about RootCollisionNode, it's handled in nifbullet --- components/nifogre/ogre_nif_loader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5f7e686a0..e276092c7 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -328,7 +328,9 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro ctrl = ctrl->next; } - if(!(node->recType == Nif::RC_NiNode)) + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); Nif::ExtraPtr e = node->extra; From da5f11700f8e6603d09a04f868fe3de112beacc4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 13 Feb 2013 00:45:00 -0800 Subject: [PATCH 612/916] Warn about unhandled node types before the controllers --- components/nifogre/ogre_nif_loader.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e276092c7..c52a73e1c 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -318,6 +318,11 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro bone->setScale(Ogre::Vector3(node->trafo.scale)); bone->setBindingPose(); + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + )) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { @@ -328,11 +333,6 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro ctrl = ctrl->next; } - if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ - )) - warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); - Nif::ExtraPtr e = node->extra; while(!e.empty()) { From 6a49ea9b4fd5726f07c17db95c620a1059f78d1f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Feb 2013 18:39:36 +0100 Subject: [PATCH 613/916] Cleaning out some old bits --- apps/openmw/mwbase/inputmanager.hpp | 3 -- apps/openmw/mwgui/settingswindow.cpp | 6 +++ apps/openmw/mwinput/inputmanagerimp.cpp | 17 ++------- apps/openmw/mwinput/inputmanagerimp.hpp | 4 -- apps/openmw/mwrender/refraction.cpp | 6 +-- apps/openmw/mwrender/refraction.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 45 +++-------------------- apps/openmw/mwrender/renderingmanager.hpp | 2 - apps/openmw/mwrender/water.cpp | 2 - 9 files changed, 16 insertions(+), 70 deletions(-) diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index f69e1a152..8293cbfa7 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -39,9 +39,6 @@ namespace MWBase virtual int getNumActions() = 0; virtual void enableDetectingBindingMode (int action) = 0; virtual void resetToDefaultBindings() = 0; - - virtual void create () = 0; - virtual void destroy () = 0; }; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index eaea022c0..73f2f6c8a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -370,6 +370,12 @@ namespace MWGui apply(); } } + else if (_sender == mVSyncButton) + { + Settings::Manager::setBool("vsync", "Video", newState); + MWBase::Environment::get().getWindowManager()-> + messageBox("VSync will be applied after a restart", std::vector()); + } else { if (_sender == mVSyncButton) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 00849503c..0934d8763 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -53,14 +53,6 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) - { - create(); - - changeInputMode(false); - } - - - void InputManager::create() { Ogre::RenderWindow* window = mOgre.getWindow (); size_t windowHnd; @@ -139,9 +131,11 @@ namespace MWInput mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; + + changeInputMode(false); } - void InputManager::destroy() + InputManager::~InputManager() { mInputCtrl->save (mUserFile); @@ -152,11 +146,6 @@ namespace MWInput OIS::InputManager::destroyInputSystem(mInputManager); } - InputManager::~InputManager() - { - destroy(); - } - void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { if (mDragDrop) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 7be35ee0b..3be669621 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -153,10 +153,6 @@ namespace MWInput std::map mControlSwitch; - public: - virtual void create(); - virtual void destroy(); - private: void adjustMouseRegion(int width, int height); diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 05229da1d..e6b6e3baa 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -31,6 +31,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); vp->setMaterialScheme("water_reflection"); + vp->setBackgroundColour (Ogre::ColourValue(0.0078, 0.0576, 0.150)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } @@ -66,11 +67,6 @@ namespace MWRender mNearClipPlaneUnderwater = Ogre::Plane( Ogre::Vector3(0,1,0), height - 5); } - void Refraction::setViewportBackground (Ogre::ColourValue colour) - { - mRenderTarget->getViewport (0)->setBackgroundColour (colour); - } - void Refraction::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) { // We don't want the sky to get clipped by custom near clip plane (the water plane) diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp index 6b3c487c1..de47d6e43 100644 --- a/apps/openmw/mwrender/refraction.hpp +++ b/apps/openmw/mwrender/refraction.hpp @@ -24,7 +24,6 @@ namespace MWRender void setHeight (float height); void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void setViewportBackground(Ogre::ColourValue colour); void setUnderwater(bool underwater) {mIsUnderwater = underwater;} void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index afbdbb06f..ce48284e0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -46,8 +46,12 @@ namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) - : mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0), mPhysicsEngine(engine), - mRecreateWindowInNextFrame(false) + : mRendering(_rend) + , mObjects(mRendering) + , mActors(mRendering) + , mAmbientMode(0) + , mSunEnabled(0) + , mPhysicsEngine(engine) { // select best shader mode bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); @@ -324,33 +328,6 @@ RenderingManager::moveObjectToCell( void RenderingManager::update (float duration, bool paused) { - if (mRecreateWindowInNextFrame) - { - mRecreateWindowInNextFrame = false; - - mRendering.removeWindowEventListener(this); - mRendering.getWindow()->removeListener(this); - MWBase::Environment::get().getInputManager()->destroy(); - - OEngine::Render::WindowSettings windowSettings; - windowSettings.fullscreen = Settings::Manager::getBool("fullscreen", "Video"); - windowSettings.window_x = Settings::Manager::getInt("resolution x", "Video"); - windowSettings.window_y = Settings::Manager::getInt("resolution y", "Video"); - windowSettings.vsync = Settings::Manager::getBool("vsync", "Video"); - std::string aa = Settings::Manager::getString("antialiasing", "Video"); - windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; - mRendering.recreateWindow("OpenMW", windowSettings); - - MWBase::Environment::get().getInputManager()->create(); - mRendering.setWindowEventListener (this); - mRendering.getWindow()->addListener(this); - - // this is necessary, otherwise it would just endlessly wait for the last query and it would never return - delete mOcclusionQuery; - mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); - } - - Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -784,7 +761,6 @@ Compositors* RenderingManager::getCompositors() void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) { bool changeRes = false; - bool recreateWindow = false; bool rebuild = false; // rebuild static geometry (necessary after any material changes) for (Settings::CategorySettingVector::const_iterator it=settings.begin(); it != settings.end(); ++it) @@ -803,8 +779,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec || it->second == "resolution y" || it->second == "fullscreen")) changeRes = true; - else if (it->first == "Video" && it->second == "vsync") - recreateWindow = true; else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); else if ((it->second == "texture filtering" && it->first == "General") @@ -876,13 +850,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } - if (recreateWindow) - { - mRecreateWindowInNextFrame = true; - // We can not do this now, because this might get triggered from the input listener - // and destroying/recreating the input system at that point would cause a crash - } - if (mWater) mWater->processChangedSettings(settings); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 670f3dc85..71ac742c2 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -260,8 +260,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList MWRender::Compositors* mCompositors; VideoPlayer* mVideoPlayer; - - bool mRecreateWindowInNextFrame; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f31dca08c..3b8705ac5 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -380,8 +380,6 @@ void Water::setViewportBackground(const ColourValue& bg) { if (mReflection) mReflection->setViewportBackground(bg); - if (mRefraction) - mRefraction->setViewportBackground(bg); } void Water::updateVisible() From 5d1bede9e50c13d72f548f23d3b5e8da60b79119 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Thu, 14 Feb 2013 11:20:47 +0100 Subject: [PATCH 614/916] Forgot to add two files --- apps/launcher/utils/comboboxlineedit.cpp | 35 ++++++++++++++++++++++++ apps/launcher/utils/comboboxlineedit.hpp | 35 ++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 apps/launcher/utils/comboboxlineedit.cpp create mode 100644 apps/launcher/utils/comboboxlineedit.hpp diff --git a/apps/launcher/utils/comboboxlineedit.cpp b/apps/launcher/utils/comboboxlineedit.cpp new file mode 100644 index 000000000..4d62e1399 --- /dev/null +++ b/apps/launcher/utils/comboboxlineedit.cpp @@ -0,0 +1,35 @@ +#include +#include + +#include "comboboxlineedit.hpp" + +ComboBoxLineEdit::ComboBoxLineEdit(QWidget *parent) + : QLineEdit(parent) +{ + mClearButton = new QToolButton(this); + QPixmap pixmap(":images/clear.png"); + mClearButton->setIcon(QIcon(pixmap)); + mClearButton->setIconSize(pixmap.size()); + mClearButton->setCursor(Qt::ArrowCursor); + mClearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }"); + mClearButton->hide(); + connect(mClearButton, SIGNAL(clicked()), this, SLOT(clear())); + connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateClearButton(const QString&))); + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + + setObjectName(QString("ComboBoxLineEdit")); + setStyleSheet(QString("ComboBoxLineEdit { background-color: transparent; padding-right: %1px; } ").arg(mClearButton->sizeHint().width() + frameWidth + 1)); +} + +void ComboBoxLineEdit::resizeEvent(QResizeEvent *) +{ + QSize sz = mClearButton->sizeHint(); + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + mClearButton->move(rect().right() - frameWidth - sz.width(), + (rect().bottom() + 1 - sz.height())/2); +} + +void ComboBoxLineEdit::updateClearButton(const QString& text) +{ + mClearButton->setVisible(!text.isEmpty()); +} diff --git a/apps/launcher/utils/comboboxlineedit.hpp b/apps/launcher/utils/comboboxlineedit.hpp new file mode 100644 index 000000000..ba10731ae --- /dev/null +++ b/apps/launcher/utils/comboboxlineedit.hpp @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (c) 2007 Trolltech ASA +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#ifndef LINEEDIT_H +#define LINEEDIT_H + +#include + +class QToolButton; + +class ComboBoxLineEdit : public QLineEdit +{ + Q_OBJECT + +public: + ComboBoxLineEdit(QWidget *parent = 0); + +protected: + void resizeEvent(QResizeEvent *); + +private slots: + void updateClearButton(const QString &text); + +private: + QToolButton *mClearButton; +}; + +#endif // LIENEDIT_H + From 492e0f2ccfbf9b069346e738f9145359a036335e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Feb 2013 19:45:07 +0100 Subject: [PATCH 615/916] Switched objects shaders to vertex lighting, to accomodate badly placed lights in morrowind. Fixed a very obvious land <-> water seam. --- files/materials/objects.shader | 83 +++++++++++++++++++++++++++++++--- files/materials/terrain.shader | 13 ++---- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 1e9c4a334..af596b779 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -22,6 +22,8 @@ #define HAS_VERTEXCOLOR @shPropertyBool(has_vertex_colour) +#define VERTEX_LIGHTING 1 + #ifdef SH_VERTEX_SHADER // ------------------------------------- VERTEX --------------------------------------- @@ -42,8 +44,24 @@ #if HAS_VERTEXCOLOR shColourInput(float4) +#if !VERTEX_LIGHTING shOutput(float4, colourPassthrough) #endif +#endif + +#if VERTEX_LIGHTING + shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) + shUniform(float4, lightPosition[8]) @shAutoConstant(lightPosition, light_position_object_space_array, 8) + shUniform(float4, lightDiffuse[8]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, 8) + shUniform(float4, lightAttenuation[8]) @shAutoConstant(lightAttenuation, light_attenuation_array, 8) + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) +#if !HAS_VERTEXCOLOUR + shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) +#endif + shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) + shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + +#endif #if SHADOWS shOutput(float4, lightSpacePos0) @@ -58,6 +76,11 @@ @shEndForeach shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) #endif + +#if VERTEX_LIGHTING + shOutput(float3, lightResult) + shOutput(float3, directionalResult) +#endif SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); @@ -74,7 +97,7 @@ objSpacePositionPassthrough = shInputPosition.xyz; #endif -#if HAS_VERTEXCOLOR +#if HAS_VERTEXCOLOR && !VERTEX_LIGHTING colourPassthrough = colour; #endif @@ -86,6 +109,36 @@ @shForeach(3) lightSpacePos@shIterator = shMatrixMult(texViewProjMatrix@shIterator, wPos); @shEndForeach +#endif + + +#if VERTEX_LIGHTING + float3 lightDir; + float d; + + @shForeach(@shGlobalSettingString(num_lights)) + lightDir = lightPosition[@shIterator].xyz - (shInputPosition.xyz * lightPosition[@shIterator].w); + d = length(lightDir); + lightDir = normalize(lightDir); + + lightResult += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz + * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * max(dot(normalize(normal.xyz), normalize(lightDir)), 0); + +#if @shIterator == 0 + directionalResult = lightResult; +#endif + + @shEndForeach + +#if HAS_VERTEXCOLOR + // ambient vertex colour tracking, FFP behaviour + lightResult += lightAmbient.xyz * colour.xyz + materialEmissive.xyz; + +#else + lightResult += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; +#endif + #endif } @@ -115,25 +168,29 @@ #if LIGHTING shInput(float3, normalPassthrough) shInput(float3, objSpacePositionPassthrough) - shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) #if !HAS_VERTEXCOLOR shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) #endif shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) +#if !VERTEX_LIGHTING + @shForeach(@shGlobalSettingString(num_lights)) shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) shUniform(float4, lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) shUniform(float4, lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) @shEndForeach #endif + +#endif #if FOG shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) #endif -#if HAS_VERTEXCOLOR +#if HAS_VERTEXCOLOR && !VERTEX_LIGHTING shInput(float4, colourPassthrough) #endif @@ -175,6 +232,11 @@ shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #endif +#if VERTEX_LIGHTING + shInput(float3, lightResult) + shInput(float3, directionalResult) +#endif + SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV); @@ -187,9 +249,9 @@ #if HAS_VERTEXCOLOR // ambient vertex colour tracking, FFP behaviour - float3 ambient = colourPassthrough.xyz * lightAmbient.xyz; + //float3 ambient = colourPassthrough.xyz * lightAmbient.xyz; #else - float3 ambient = materialAmbient.xyz * lightAmbient.xyz; + //float3 ambient = materialAmbient.xyz * lightAmbient.xyz; #endif // shadows only for the first (directional) light @@ -228,6 +290,7 @@ caustics = float3(1,1,1); #endif +#if !VERTEX_LIGHTING @shForeach(@shGlobalSettingString(num_lights)) @@ -253,9 +316,16 @@ @shEndForeach - shOutputColour(0).xyz *= (ambient + diffuse + materialEmissive.xyz); + lightResult = (ambient + diffuse + materialEmissive.xyz); #endif +#if SHADOWS + shOutputColour(0).xyz *= (lightResult - directionalResult * (1.0-shadow)); +#else + shOutputColour(0).xyz *= (lightResult); +#endif + +#endif // IF LIGHTING #if HAS_VERTEXCOLOR && !LIGHTING shOutputColour(0).xyz *= colourPassthrough.xyz; @@ -303,7 +373,6 @@ #if MRT shOutputColour(1) = float4(depthPassthrough / far,1,1,1); #endif - } #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 9b891e1e8..d62bb4035 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -32,7 +32,7 @@ @shAllocatePassthrough(2, UV) #if LIGHTING -@shAllocatePassthrough(3, objSpacePosition) +@shAllocatePassthrough(3, worldPos) #endif #if SHADOWS @@ -101,7 +101,7 @@ @shPassthroughAssign(UV, uv0); #if LIGHTING - @shPassthroughAssign(objSpacePosition, shInputPosition.xyz); + @shPassthroughAssign(worldPos, worldPos.xyz); #endif #if SHADOWS @@ -162,7 +162,7 @@ #if LIGHTING shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) @shForeach(@shGlobalSettingString(terrain_num_lights)) - shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) + shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position, @shIterator) shUniform(float4, lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) shUniform(float4, lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) @shEndForeach @@ -213,7 +213,7 @@ float2 UV = @shPassthroughReceive(UV); #if LIGHTING - float3 objSpacePosition = @shPassthroughReceive(objSpacePosition); + float3 worldPos = @shPassthroughReceive(worldPos); float3 normal = shSample(normalMap, UV).rgb * 2 - 1; normal = normalize(normal); @@ -222,9 +222,6 @@ float3 caustics = float3(1,1,1); -#if (UNDERWATER) || (FOG) - float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePosition,1)).xyz; -#endif #if UNDERWATER @@ -306,7 +303,7 @@ @shForeach(@shGlobalSettingString(terrain_num_lights)) - lightDir = lightPosObjSpace@shIterator.xyz - (objSpacePosition.xyz * lightPosObjSpace@shIterator.w); + lightDir = lightPosObjSpace@shIterator.xyz - (worldPos.xyz * lightPosObjSpace@shIterator.w); d = length(lightDir); From 7604fb51b66a63a1f9b0256447982b1e65024b81 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Feb 2013 23:17:21 +0100 Subject: [PATCH 616/916] CG no longer listed in the settings if the plugin isn't loaded. --- apps/openmw/mwgui/settingswindow.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 73f2f6c8a..54c2ef197 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -77,6 +78,17 @@ namespace { return (Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") != std::string::npos) ? "glsl" : "hlsl"; } + + bool cgAvailable () + { + Ogre::Root::PluginInstanceList list = Ogre::Root::getSingleton ().getInstalledPlugins (); + for (Ogre::Root::PluginInstanceList::const_iterator it = list.begin(); it != list.end(); ++it) + { + if ((*it)->getName() == "Cg Program Manager") + return true; + } + return false; + } } namespace MWGui @@ -428,7 +440,7 @@ namespace MWGui { val = hlslGlsl(); } - else + else if (cgAvailable ()) val = "cg"; static_cast(_sender)->setCaption(val); From 1b9cf8c23fbcbc6591bcd45bd29fb6a34f5007c7 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Fri, 15 Feb 2013 01:20:48 +0100 Subject: [PATCH 617/916] More work on integrating the settings parser, profiles are handled correctly --- apps/launcher/datafilespage.cpp | 71 +++++++++++++++++---- apps/launcher/settings/launchersettings.cpp | 54 ++++++++++++++++ apps/launcher/settings/launchersettings.hpp | 3 + apps/launcher/settings/settingsbase.hpp | 16 +++-- apps/launcher/utils/profilescombobox.cpp | 28 ++++---- 5 files changed, 140 insertions(+), 32 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 12323b1f1..678f8cc3c 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -293,22 +293,77 @@ void DataFilesPage::setupDataFiles() mPluginsModel->addPlugins(dataLocal); } + QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); + QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + + mProfilesComboBox->addItems(profiles); + + // Add the current profile if empty + if (mProfilesComboBox->findText(profile) == -1) + mProfilesComboBox->addItem(profile); + + if (mProfilesComboBox->findText(QString("Default")) == -1) + mProfilesComboBox->addItem(QString("Default")); + + if (profile.isEmpty()) { + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(QString("Default"))); + } else { + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); + } + loadSettings(); } void DataFilesPage::loadSettings() { qDebug() << "load settings"; + QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + + qDebug() << mLauncherSettings.values(QString("Profiles/Default"), Qt::MatchStartsWith); + + + + if (profile.isEmpty()) + return; + + + mMastersModel->uncheckAll(); + mPluginsModel->uncheckAll(); + + QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly); + QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly); + qDebug() << "masters to check " << plugins; + + foreach (const QString &master, masters) { + QModelIndex index = mMastersModel->indexFromItem(mMastersModel->findItem(master)); + if (index.isValid()) + mMastersModel->setCheckState(index, Qt::Checked); + } + + foreach (const QString &plugin, plugins) { + QModelIndex index = mPluginsModel->indexFromItem(mPluginsModel->findItem(plugin)); + if (index.isValid()) + mPluginsModel->setCheckState(index, Qt::Checked); + } } void DataFilesPage::saveSettings() { QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + + if (profile.isEmpty()) { + profile = mProfilesComboBox->currentText(); + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), profile); + } + qDebug() << "save settings" << profile; + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); QStringList items = mMastersModel->checkedItems(); foreach(const QString &master, items) { + qDebug() << "setting " << master; mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), master); } @@ -482,17 +537,11 @@ void DataFilesPage::writeConfig(QString profile) void DataFilesPage::newProfile() { -// if (mNewProfileDialog->exec() == QDialog::Accepted) { - -// const QString text = mNewProfileDialog->lineEdit()->text(); -// mProfilesComboBox->addItem(text); -// mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(text)); -// } - - mDeleteProfileAction->setEnabled(false); - mProfilesComboBox->setCurrentIndex(-1); - mProfilesComboBox->setEditEnabled(true); - mProfilesComboBox->lineEdit()->setFocus(); + if (mNewProfileDialog->exec() == QDialog::Accepted) { + QString profile = mNewProfileDialog->lineEdit()->text(); + mProfilesComboBox->addItem(profile); + mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); + } } void DataFilesPage::updateOkButton(const QString &text) diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index c189c282f..07502ea02 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -13,6 +13,60 @@ LauncherSettings::~LauncherSettings() { } +QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags) +{ + QMap settings = SettingsBase::getSettings(); + + if (flags == Qt::MatchExactly) + return settings.values(key); + + QStringList result; + + if (flags == Qt::MatchStartsWith) { + QStringList keys = settings.keys(); + + foreach (const QString ¤tKey, keys) { + qDebug() << "key is: " << currentKey << "value: " << settings.value(currentKey); + if (currentKey.startsWith(key)) + result.append(settings.value(currentKey)); + } + } + + return result; +} + +QStringList LauncherSettings::subKeys(const QString &key) +{ + QMap settings = SettingsBase::getSettings(); + QStringList keys = settings.keys(); + + QRegExp keyRe("(.+)/"); + + QStringList result; + + foreach (const QString ¤tKey, keys) { + qDebug() << "key is: " << currentKey; + if (keyRe.indexIn(currentKey) != -1) { + qDebug() << "text: " << keyRe.cap(1) << keyRe.cap(2); + + QString prefixedKey = keyRe.cap(1); + if(prefixedKey.startsWith(key)) { + + QString subKey = prefixedKey.remove(key); + if (!subKey.isEmpty()) + result.append(subKey); + //qDebug() << keyRe.cap(2).simplified(); + } + } else { + qDebug() << "no match"; + } + } + + result.removeDuplicates(); + qDebug() << result; + + return result; +} bool LauncherSettings::writeFile(QTextStream &stream) { diff --git a/apps/launcher/settings/launchersettings.hpp b/apps/launcher/settings/launchersettings.hpp index cf4dd4c9f..d78a75d45 100644 --- a/apps/launcher/settings/launchersettings.hpp +++ b/apps/launcher/settings/launchersettings.hpp @@ -9,6 +9,9 @@ public: LauncherSettings(); ~LauncherSettings(); + QStringList subKeys(const QString &key); + QStringList values(const QString &key, Qt::MatchFlags flags = Qt::MatchExactly); + bool writeFile(QTextStream &stream); }; diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index e09ea6203..361884da6 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -24,12 +24,20 @@ public: inline void setValue(const QString &key, const QString &value) { - mSettings.insert(key, value); + QStringList values = mSettings.values(key); + if (!values.contains(value)) + mSettings.insert(key, value); } inline void setMultiValue(const QString &key, const QString &value) { - mSettings.insertMulti(key, value); + QStringList values = mSettings.values(key); + if (!values.contains(value)) { + qDebug() << "inserting " << value; + mSettings.insertMulti(key, value); + } else { + qDebug() << "not inserting " << value; + } } @@ -73,13 +81,11 @@ public: QStringList values = mCache.values(key); if (!values.contains(value)) { // QMap will replace the value if key exists, QMultiMap creates a new one - mCache.insert(key, value); + mCache.insertMulti(key, value); } } } - qDebug() << "HI THERE! " << mCache; - if (mSettings.isEmpty()) { mSettings = mCache; // This is the first time we read a file return true; diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp index 3a75ba417..a2c8668cb 100644 --- a/apps/launcher/utils/profilescombobox.cpp +++ b/apps/launcher/utils/profilescombobox.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "profilescombobox.hpp" #include "comboboxlineedit.hpp" @@ -18,12 +19,11 @@ ProfilesComboBox::ProfilesComboBox(QWidget *parent) : connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotIndexChanged(int))); - + setInsertPolicy(QComboBox::NoInsert); } void ProfilesComboBox::setEditEnabled(bool editable) { - qDebug() << "called"; if (isEditable() == editable) return; @@ -50,29 +50,25 @@ void ProfilesComboBox::setEditEnabled(bool editable) void ProfilesComboBox::slotTextChanged(const QString &text) { - QString previous = itemText(currentIndex()); -// lineEdit()->setPalette(QApplication::palette()); + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Text,Qt::red); - if (text.isEmpty()) - return; + int index = findText(text); - if (text == previous) - return; - - qDebug() << "textChanged"; - if (findText(text) != -1) { - QPalette *palette = new QPalette(); - palette->setColor(QPalette::Text,Qt::red); + if (text.isEmpty() || (index != -1 && index != currentIndex())) { lineEdit()->setPalette(*palette); + } else { + lineEdit()->setPalette(QApplication::palette()); } } void ProfilesComboBox::slotEditingFinished() { - qDebug() << "returnpressed"; QString current = currentText(); QString previous = itemText(currentIndex()); + qDebug() << current << previous; + if (current.isEmpty()) return; @@ -82,9 +78,9 @@ void ProfilesComboBox::slotEditingFinished() if (findText(current) != -1) return; - if (currentIndex() == -1) { - addItem(currentText()); + addItem(current); + setCurrentIndex(findText(current)); } else { setItemText(currentIndex(), current); emit(profileRenamed(previous, current)); From a729b1b12a6502e7382c8a2bb3f79ed1e808bce1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 18:34:51 -0800 Subject: [PATCH 618/916] Snap to the ground after moving Depends on two factors: * End up close enough above to a walkable plane (it's within sMaxStep units down and is angled sMaxSlope or less) * Started out on the ground without any upward movement This also reduces the distance needed to be to the ground to 4 (from 10), and ensures the actor is 2 units above the ground when on it. Downward force is also removed when starting on the ground. --- apps/openmw/mwworld/physicssystem.cpp | 31 ++++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a5dd7f369..7a343604c 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -102,6 +102,7 @@ namespace MWWorld } traceResults trace; //no initialization needed + bool onground = false; float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); @@ -117,22 +118,24 @@ namespace MWWorld } else { + if(!(movement.z > 0.0f)) + { + newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) + onground = true; + } + velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * movement / time; - velocity.z = physicActor->getVerticalForce(); + velocity.z += physicActor->getVerticalForce(); } - // we need a copy of the velocity before we start clipping it for steps Ogre::Vector3 clippedVelocity(velocity); - - if(gravity) + if(onground) { - newtrace(&trace, position, position+Ogre::Vector3(0,0,-10), halfExtents, verticalRotation, isInterior, engine); - if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) - { - // if we're within 10 units of the ground, force velocity to track the ground - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); - } + // if we're on the ground, force velocity to track it + clippedVelocity.z = velocity.z = std::max(0.0f, velocity.z); + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } Ogre::Vector3 lastNormal(0.0f); @@ -176,6 +179,14 @@ namespace MWWorld iterations++; } while(iterations < sMaxIterations && remainingTime > 0.0f); + if(onground) + { + newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, verticalRotation, isInterior, engine); + if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) + newPosition.z = trace.endpos.z + 2.0f; + else + onground = false; + } physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; From 15dc82f4545d78318ec7d3655df22fd569615800 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 18:59:05 -0800 Subject: [PATCH 619/916] Increase step size to 15 --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7a343604c..447c1fa2a 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -26,7 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; - static const float sStepSize = 9.0f; + static const float sStepSize = 15.0f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 50; From 18b606fddff13307d1b9700e548de5dddb0e550a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 20:10:04 -0800 Subject: [PATCH 620/916] Use the PhysicActor's set/getOnGround method --- apps/openmw/mwworld/physicssystem.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 8 ++------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 447c1fa2a..423666563 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -187,6 +187,7 @@ namespace MWWorld else onground = false; } + physicActor->setOnGround(onground); physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); return newPosition; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2b42e6f06..77e29f9be 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1418,17 +1418,13 @@ namespace MWWorld RefData &refdata = mPlayer->getPlayer().getRefData(); Ogre::Vector3 playerPos(refdata.getPosition().pos); - std::pair hit = mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); - bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); - - if(!isOnGround || isUnderwater(*currentCell->mCell, playerPos)) + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + if(!physactor->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) return 2; - if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; return 0; - } MWRender::Animation* World::getAnimation(const MWWorld::Ptr &ptr) From ac717373b1a47618a0392cd33da7c1bd836fc630 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 22:35:15 -0800 Subject: [PATCH 621/916] Add a method to check if an object is on the ground --- apps/openmw/mwbase/world.hpp | 5 +++-- apps/openmw/mwworld/worldimp.cpp | 11 +++++++++-- apps/openmw/mwworld/worldimp.hpp | 5 +++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3b71d421c..278c0d0a9 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -286,8 +286,9 @@ namespace MWBase virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; - virtual bool isSwimming(const MWWorld::Ptr &object) = 0; - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) = 0; + virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; + virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const = 0; + virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual void togglePOV() = 0; virtual void togglePreviewMode(bool enable) = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 77e29f9be..f2d2e2c00 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1379,7 +1379,7 @@ namespace MWWorld } bool - World::isSwimming(const MWWorld::Ptr &object) + World::isSwimming(const MWWorld::Ptr &object) const { /// \todo add check ifActor() - only actors can swim float *fpos = object.getRefData().getPosition().pos; @@ -1393,7 +1393,7 @@ namespace MWWorld } bool - World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) + World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const { if (!(cell.mData.mFlags & ESM::Cell::HasWater)) { return false; @@ -1401,6 +1401,13 @@ namespace MWWorld return pos.z < cell.mWater; } + bool World::isOnGround(const MWWorld::Ptr &ptr) const + { + RefData &refdata = ptr.getRefData(); + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + return physactor && physactor->getOnGround(); + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d7b20ba17..39c87fce7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -314,8 +314,9 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); - virtual bool isSwimming(const MWWorld::Ptr &object); - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos); + virtual bool isSwimming(const MWWorld::Ptr &object) const; + virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const; + virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { mRendering->togglePOV(); From 3348e8a436081c4ebbfbe39fd8296056be3c75d6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 14 Feb 2013 22:41:14 -0800 Subject: [PATCH 622/916] Clarify a comment --- apps/openmw/mwmechanics/character.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index d67964b84..eb3907041 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,7 +45,7 @@ enum CharacterState { CharState_SwimRunLeft, CharState_SwimRunRight, - /* Must be last! */ + /* Death states must be last! */ CharState_Death1, CharState_Death2, CharState_Death3, From e1a1530774bdb21bd2314b9bd2e48947cf198933 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 01:27:57 -0800 Subject: [PATCH 623/916] Better implement Npc::getSpeed --- apps/openmw/mwclass/npc.cpp | 84 +++++++++++++++++++++++++++++++++++-- apps/openmw/mwclass/npc.hpp | 17 ++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3666d9d6b..d135d2683 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -55,9 +55,30 @@ namespace MWClass { void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const { + static bool inited = false; + if(!inited) + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + fMinWalkSpeed = gmst.find("fMinWalkSpeed"); + fMaxWalkSpeed = gmst.find("fMaxWalkSpeed"); + fEncumberedMoveEffect = gmst.find("fEncumberedMoveEffect"); + fSneakSpeedMultiplier = gmst.find("fSneakSpeedMultiplier"); + fAthleticsRunBonus = gmst.find("fAthleticsRunBonus"); + fBaseRunMultiplier = gmst.find("fBaseRunMultiplier"); + fMinFlySpeed = gmst.find("fMinFlySpeed"); + fMaxFlySpeed = gmst.find("fMaxFlySpeed"); + fSwimRunBase = gmst.find("fSwimRunBase"); + fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult"); + // Added in Tribunal/Bloodmoon, may not exist + fWereWolfRunMult = gmst.search("fWereWolfRunMult"); + + inited = true; + } if (!ptr.getRefData().getCustomData()) { - std::auto_ptr data (new CustomData); + std::auto_ptr data(new CustomData); MWWorld::LiveCellRef *ref = ptr.get(); @@ -297,9 +318,54 @@ namespace MWClass return false; } - float Npc::getSpeed (const MWWorld::Ptr& ptr) const + float Npc::getSpeed(const MWWorld::Ptr& ptr) const { - return getStance (ptr, Run) ? 600 : 300; // TODO calculate these values from stats + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr); + + float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified()* + (fMaxWalkSpeed->getFloat() - fMinWalkSpeed->getFloat()); + walkSpeed *= 1.0f - fEncumberedMoveEffect->getFloat()*normalizedEncumbrance; + walkSpeed = std::max(0.0f, walkSpeed); + if(Npc::getStance(ptr, Sneak, false)) + walkSpeed *= fSneakSpeedMultiplier->getFloat(); + float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * + fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); + + float moveSpeed; + if(normalizedEncumbrance > 1.0f) + moveSpeed = 0.0f; + else if(0/*world->isFlying(ptr)*/) + { + float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + + 0.0f/*levitationBonus*/); + flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); + flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; + flySpeed = std::max(0.0f, flySpeed); + moveSpeed = flySpeed; + } + else if(world->isSwimming(ptr)) + { + float swimSpeed = walkSpeed; + if(Npc::getStance(ptr, Run, false)) + swimSpeed = runSpeed; + swimSpeed *= 1.0f + 0.01f * 0.0f/*swiftSwimBonus*/; + swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* + fSwimRunAthleticsMult->getFloat(); + moveSpeed = swimSpeed; + } + else if(Npc::getStance(ptr, Run, false)) + moveSpeed = runSpeed; + else + moveSpeed = walkSpeed; + + if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) + moveSpeed *= 0.75f; + if(npcdata->mNpcStats.isWerewolf() && Npc::getStance(ptr, Run, false)) + moveSpeed *= fWereWolfRunMult->getFloat(); + + return moveSpeed; } MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const @@ -416,4 +482,16 @@ namespace MWClass return MWWorld::Ptr(&cell.mNpcs.insert(*ref), &cell); } + + const ESM::GameSetting *Npc::fMinWalkSpeed; + const ESM::GameSetting *Npc::fMaxWalkSpeed; + const ESM::GameSetting *Npc::fEncumberedMoveEffect; + const ESM::GameSetting *Npc::fSneakSpeedMultiplier; + const ESM::GameSetting *Npc::fAthleticsRunBonus; + const ESM::GameSetting *Npc::fBaseRunMultiplier; + const ESM::GameSetting *Npc::fMinFlySpeed; + const ESM::GameSetting *Npc::fMaxFlySpeed; + const ESM::GameSetting *Npc::fSwimRunBase; + const ESM::GameSetting *Npc::fSwimRunAthleticsMult; + const ESM::GameSetting *Npc::fWereWolfRunMult; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 20c2da4b1..a97e4c42e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -3,6 +3,11 @@ #include "../mwworld/class.hpp" +namespace ESM +{ + class GameSetting; +} + namespace MWClass { class Npc : public MWWorld::Class @@ -12,6 +17,18 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + static const ESM::GameSetting *fMinWalkSpeed; + static const ESM::GameSetting *fMaxWalkSpeed; + static const ESM::GameSetting *fEncumberedMoveEffect; + static const ESM::GameSetting *fSneakSpeedMultiplier; + static const ESM::GameSetting *fAthleticsRunBonus; + static const ESM::GameSetting *fBaseRunMultiplier; + static const ESM::GameSetting *fMinFlySpeed; + static const ESM::GameSetting *fMaxFlySpeed; + static const ESM::GameSetting *fSwimRunBase; + static const ESM::GameSetting *fSwimRunAthleticsMult; + static const ESM::GameSetting *fWereWolfRunMult; + public: virtual std::string getId (const MWWorld::Ptr& ptr) const; From ff0099fa6e89c97f5f269d2f25adc66a5540edfc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 02:15:39 -0800 Subject: [PATCH 624/916] Scale the animation speed based on the animation velocity and movement speed This may not be totoally correct since it takes the whole animation into account, rather than just the looping portion. But it's good enough for now. --- apps/openmw/mwmechanics/character.cpp | 5 ++-- apps/openmw/mwrender/animation.cpp | 33 +++++++++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 4 ++-- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b6e96bdf5..c40fac40a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,6 +172,7 @@ Ogre::Vector3 CharacterController::update(float duration) { const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + const float speed = cls.getSpeed(mPtr); bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); @@ -204,9 +205,7 @@ Ogre::Vector3 CharacterController::update(float duration) Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) { - // FIXME: The speed should actually be determined by the character's - // stance (running, sneaking, etc) and stats - mAnimation->setSpeedMult(1.0f); + mAnimation->setSpeed(speed); movement += mAnimation->runAnimation(duration); } mSkipAnim = false; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 9d9631ece..1a606992a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -28,6 +28,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentTime(0.0f) , mPlaying(false) , mLooping(false) + , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { } @@ -161,6 +162,13 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum) mAccumulate = accum; } +void Animation::setSpeed(float speed) +{ + mAnimSpeedMult = 1.0f; + if(mAnimVelocity > 1.0f && speed > 0.0f) + mAnimSpeedMult = speed / mAnimVelocity; +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { @@ -255,6 +263,31 @@ void Animation::play(const std::string &groupname, const std::string &start, boo { mCurrentAnim = (*iter)->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mAnimVelocity = 0.0f; + + if(mNonAccumRoot) + { + const Ogre::NodeAnimationTrack *track = 0; + + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track && track->getNumKeyFrames() > 1) + { + const Ogre::TransformKeyFrame *startkf, *endkf; + startkf = static_cast(track->getKeyFrame(0)); + endkf = static_cast(track->getKeyFrame(track->getNumKeyFrames() - 1)); + + mAnimVelocity = startkf->getTranslate().distance(endkf->getTranslate()) / + mCurrentAnim->getLength(); + } + } + found = true; break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index ee73193bf..fc35c06be 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -36,6 +36,7 @@ protected: bool mPlaying; bool mLooping; + float mAnimVelocity; float mAnimSpeedMult; /* Applies the given animation to the given skeleton instance, using the specified time. */ @@ -73,8 +74,7 @@ public: // should be on the scale of 0 to 1. void setAccumulation(const Ogre::Vector3 &accum); - void setSpeedMult(float speedmult) - { mAnimSpeedMult = speedmult; } + void setSpeed(float speed); void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); From e4341525c859a94250de4c09165737cdd81b64e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 04:45:28 -0800 Subject: [PATCH 625/916] Add a jump state Currently unused --- apps/openmw/mwmechanics/character.cpp | 5 ++++- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c40fac40a..376092256 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -68,6 +68,8 @@ static const struct { { CharState_SwimRunLeft, "swimrunleft" }, { CharState_SwimRunRight, "swimrunright" }, + { CharState_Jump, "jump" }, + { CharState_Death1, "death1" }, { CharState_Death2, "death2" }, { CharState_Death3, "death3" }, @@ -170,11 +172,12 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); const float speed = cls.getSpeed(mPtr); - bool inwater = MWBase::Environment::get().getWorld()->isSwimming(mPtr); + bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); if(std::abs(vec.x/2.0f) > std::abs(vec.y)) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index eb3907041..996687a3e 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -45,6 +45,8 @@ enum CharacterState { CharState_SwimRunLeft, CharState_SwimRunRight, + CharState_Jump, + /* Death states must be last! */ CharState_Death1, CharState_Death2, From c57001e3bdda8a0b60eef303a49c4cf3eddd5f70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 05:11:06 -0800 Subject: [PATCH 626/916] Remove an unused field --- apps/openmw/mwworld/physicssystem.cpp | 4 +--- apps/openmw/mwworld/physicssystem.hpp | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 423666563..240f1c435 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -196,7 +196,7 @@ namespace MWWorld PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : - mRender(_rend), mEngine(0), mFreeFly (true) + mRender(_rend), mEngine(0) { // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); @@ -460,12 +460,10 @@ namespace MWWorld if(cmode) { act->enableCollisions(false); - mFreeFly = true; return false; } else { - mFreeFly = false; act->enableCollisions(true); return true; } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index cbdd9935e..60c8246ae 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -85,7 +85,6 @@ namespace MWWorld OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; - bool mFreeFly; std::map handleToMesh; PhysicsSystem (const PhysicsSystem&); From 990895fd2b9aab702c79a8e48fba2b6b6e3cf1c3 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Fri, 15 Feb 2013 14:12:25 +0100 Subject: [PATCH 627/916] Mainwindow size and position now gets saved/restored --- apps/launcher/maindialog.cpp | 14 ++++++++++++++ apps/launcher/utils/profilescombobox.cpp | 12 +++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index f48ea603b..7b453671c 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -169,6 +169,7 @@ bool MainDialog::setup() return false; } + loadSettings(); return true; } @@ -182,7 +183,14 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) void MainDialog::loadSettings() { + int width = mLauncherSettings.value(QString("General/MainWindow/width")).toInt(); + int height = mLauncherSettings.value(QString("General/MainWindow/height")).toInt(); + int posX = mLauncherSettings.value(QString("General/MainWindow/posx")).toInt(); + int posY = mLauncherSettings.value(QString("General/MainWindow/posy")).toInt(); + + resize(width, height); + move(posX, posY); } void MainDialog::saveSettings() @@ -193,6 +201,12 @@ void MainDialog::saveSettings() mLauncherSettings.setValue(QString("General/MainWindow/width"), width); mLauncherSettings.setValue(QString("General/MainWindow/height"), height); + QString posX = QString::number(this->pos().x()); + QString posY = QString::number(this->pos().y()); + + mLauncherSettings.setValue(QString("General/MainWindow/posx"), posX); + mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY); + qDebug() << "size: " << width << height; } diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp index a2c8668cb..4c258dae6 100644 --- a/apps/launcher/utils/profilescombobox.cpp +++ b/apps/launcher/utils/profilescombobox.cpp @@ -69,6 +69,9 @@ void ProfilesComboBox::slotEditingFinished() qDebug() << current << previous; + if (currentIndex() == -1) + return; + if (current.isEmpty()) return; @@ -78,13 +81,8 @@ void ProfilesComboBox::slotEditingFinished() if (findText(current) != -1) return; - if (currentIndex() == -1) { - addItem(current); - setCurrentIndex(findText(current)); - } else { - setItemText(currentIndex(), current); - emit(profileRenamed(previous, current)); - } + setItemText(currentIndex(), current); + emit(profileRenamed(previous, current)); } void ProfilesComboBox::slotIndexChanged(int index) From 43e9ad87331d073d69c5d571acad50020263f849 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Fri, 15 Feb 2013 14:26:09 +0100 Subject: [PATCH 628/916] The text color of the profiles dialog now turns red on invalid names --- apps/launcher/utils/textinputdialog.cpp | 46 ++++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/launcher/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp index 16cadb661..ec72e5432 100644 --- a/apps/launcher/utils/textinputdialog.cpp +++ b/apps/launcher/utils/textinputdialog.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -17,9 +18,19 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid mButtonBox->addButton(QDialogButtonBox::Ok); mButtonBox->addButton(QDialogButtonBox::Cancel); - setMaximumHeight(height()); - setOkButtonEnabled(false); - setModal(true); + // Line edit + QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore + mLineEdit = new LineEdit(this); + mLineEdit->setValidator(validator); + mLineEdit->setCompleter(0); + + QLabel *label = new QLabel(this); + label->setText(text); + + QVBoxLayout *dialogLayout = new QVBoxLayout(this); + dialogLayout->addWidget(label); + dialogLayout->addWidget(mLineEdit); + dialogLayout->addWidget(mButtonBox); // Messageboxes on mac have no title #ifndef Q_OS_MAC @@ -28,22 +39,13 @@ TextInputDialog::TextInputDialog(const QString& title, const QString &text, QWid Q_UNUSED(title); #endif - QLabel *label = new QLabel(this); - label->setText(text); - - // Line edit - QValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore - mLineEdit = new LineEdit(this); - mLineEdit->setValidator(validator); - mLineEdit->setCompleter(0); - - QVBoxLayout *dialogLayout = new QVBoxLayout(this); - dialogLayout->addWidget(label); - dialogLayout->addWidget(mLineEdit); - dialogLayout->addWidget(mButtonBox); + setMaximumHeight(height()); + setOkButtonEnabled(false); + setModal(true); connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); + } int TextInputDialog::exec() @@ -55,7 +57,17 @@ int TextInputDialog::exec() void TextInputDialog::setOkButtonEnabled(bool enabled) { - QPushButton *okButton = mButtonBox->button(QDialogButtonBox::Ok); okButton->setEnabled(enabled); + + QPalette *palette = new QPalette(); + palette->setColor(QPalette::Text,Qt::red); + + if (enabled) { + mLineEdit->setPalette(QApplication::palette()); + } else { + // Existing profile name, make the text red + mLineEdit->setPalette(*palette); + } + } From 4da11a96a5d51c0c22b62e033fb46ffaa7823f6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 Feb 2013 17:34:55 +0100 Subject: [PATCH 629/916] Fixed gold ref count always becoming 1 when dropped on the ground --- apps/openmw/mwclass/misc.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 94d40bcb7..a21cc2aef 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -210,6 +210,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell); + newPtr.getRefData ().setCount(goldAmount); } else { MWWorld::LiveCellRef *ref = ptr.get(); From df5919f2c59eeca4d38dd60b888d2aff019548b9 Mon Sep 17 00:00:00 2001 From: Douglas Mencken Date: Sat, 2 Feb 2013 10:17:20 -0500 Subject: [PATCH 630/916] Use `signed char' explicitly where needed. It is important because: - It is implementation-dependent if plain `char' signed or not. - C standard defines three *distinct* types: char, signed char, and unsigned char. - Assuming that char is always unsigned or signed can lead to compile-time and run-time errors. You can also use int8_t, but then it would be less obvious for developers to never assume that char is always unsigned (or always signed). Conflicts: components/esm/loadcell.hpp --- apps/esmtool/labels.cpp | 16 ++++++++-------- apps/esmtool/labels.hpp | 6 +++--- components/esm/loadcell.hpp | 12 ++++++------ components/esm/loaddial.hpp | 2 +- components/to_utf8/tables_gen.hpp | 6 +++--- components/to_utf8/to_utf8.cpp | 2 +- components/to_utf8/to_utf8.hpp | 2 +- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 9fb233237..d7d3cf9ce 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -16,7 +16,7 @@ #include #include -std::string bodyPartLabel(char idx) +std::string bodyPartLabel(signed char idx) { const char *bodyPartLabels[] = { "Head", @@ -47,14 +47,14 @@ std::string bodyPartLabel(char idx) "Weapon", "Tail" }; - + if ((int)idx >= 0 && (int)(idx) <= 26) return bodyPartLabels[(int)(idx)]; else return "Invalid"; } -std::string meshPartLabel(char idx) +std::string meshPartLabel(signed char idx) { const char *meshPartLabels[] = { "Head", @@ -73,25 +73,25 @@ std::string meshPartLabel(char idx) "Clavicle", "Tail" }; - + if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MP_Tail) return meshPartLabels[(int)(idx)]; else return "Invalid"; } -std::string meshTypeLabel(char idx) +std::string meshTypeLabel(signed char idx) { const char *meshTypeLabels[] = { "Skin", "Clothing", "Armor" }; - + if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MT_Armor) return meshTypeLabels[(int)(idx)]; else - return "Invalid"; + return "Invalid"; } std::string clothingTypeLabel(int idx) @@ -108,7 +108,7 @@ std::string clothingTypeLabel(int idx) "Ring", "Amulet" }; - + if (idx >= 0 && idx <= 9) return clothingTypeLabels[idx]; else diff --git a/apps/esmtool/labels.hpp b/apps/esmtool/labels.hpp index 7f1ff7986..bf3958037 100644 --- a/apps/esmtool/labels.hpp +++ b/apps/esmtool/labels.hpp @@ -3,9 +3,9 @@ #include -std::string bodyPartLabel(char idx); -std::string meshPartLabel(char idx); -std::string meshTypeLabel(char idx); +std::string bodyPartLabel(signed char idx); +std::string meshPartLabel(signed char idx); +std::string meshTypeLabel(signed char idx); std::string clothingTypeLabel(int idx); std::string armorTypeLabel(int idx); std::string dialogTypeLabel(int idx); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 27bdd77ce..de467666e 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -77,8 +77,8 @@ public: std::string mKey, mTrap; // Key and trap ID names, if any // No idea - occurs ONCE in Morrowind.esm, for an activator - char mUnam; - + signed char mUnam; + // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. int mDeleted; @@ -164,14 +164,14 @@ struct Cell bool mWaterInt; int mMapColor; int mNAM0; - + // References "leased" from another cell (i.e. a different cell // introduced this ref, and it has been moved here by a plugin) CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; - + void load(ESMReader &esm, MWWorld::ESMStore &store); - + // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. void load(ESMReader &esm) {}; @@ -209,7 +209,7 @@ struct Cell reuse one memory location without blanking it between calls. */ static bool getNextRef(ESMReader &esm, CellRef &ref); - + /* This fetches an MVRF record, which is used to track moved references. * Since they are comparably rare, we use a separate method for this. */ diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 078c78811..61f3f763d 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -30,7 +30,7 @@ struct Dialogue }; std::string mId; - char mType; + signed char mType; std::vector mInfo; void load(ESMReader &esm); diff --git a/components/to_utf8/tables_gen.hpp b/components/to_utf8/tables_gen.hpp index 9c32f0427..a1d4b6d80 100644 --- a/components/to_utf8/tables_gen.hpp +++ b/components/to_utf8/tables_gen.hpp @@ -8,7 +8,7 @@ namespace ToUTF8 /// Central European and Eastern European languages that use Latin script, /// such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, /// Serbian (Latin script), Romanian and Albanian. -static char windows_1250[] = +static signed char windows_1250[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, @@ -270,7 +270,7 @@ static char windows_1250[] = /// Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic /// and other languages -static char windows_1251[] = +static signed char windows_1251[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, @@ -531,7 +531,7 @@ static char windows_1251[] = }; /// Latin alphabet used by English and some other Western languages -static char windows_1252[] = +static signed char windows_1252[] = { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 275f5483f..e2a1b1220 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -216,7 +216,7 @@ void Utf8Encoder::copyFromArray(unsigned char ch, char* &out) return; } - const char *in = translationArray + ch*6; + const signed char *in = translationArray + ch*6; int len = *(in++); for (int i=0; i mOutput; - char* translationArray; + signed char* translationArray; }; } From c965bd8e181b0bf9a81df51b11770e97f49711ae Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 15 Feb 2013 17:22:55 -0800 Subject: [PATCH 631/916] Increase step size to 30 --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 240f1c435..058160595 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -26,7 +26,7 @@ namespace MWWorld { static const float sMaxSlope = 60.0f; - static const float sStepSize = 15.0f; + static const float sStepSize = 30.0f; // Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared. static const int sMaxIterations = 50; From 158e18b98d879b4ba9d87c8a1bc6d72d5320db65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 16 Feb 2013 00:30:07 -0800 Subject: [PATCH 632/916] Remove an unused method --- apps/openmw/mwbase/world.hpp | 3 --- apps/openmw/mwworld/worldimp.hpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 278c0d0a9..da670cf23 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -307,9 +307,6 @@ namespace MWBase /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) - /// \todo Probably shouldn't be here - virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const = 0; - /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr) = 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 39c87fce7..8b9b39617 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -349,10 +349,6 @@ namespace MWWorld /// 2 - player is underwater \n /// 3 - enemies are nearby (not implemented) - /// \todo Probably shouldn't be here - virtual OEngine::Physic::PhysicEngine* getPhysicEngine() const - { return mPhysEngine; } - /// \todo Probably shouldn't be here virtual MWRender::Animation* getAnimation(const MWWorld::Ptr &ptr); From a3e421167b3703e9943d82fb804073c99ac55651 Mon Sep 17 00:00:00 2001 From: Douglas Mencken Date: Sat, 9 Feb 2013 15:11:09 -0500 Subject: [PATCH 633/916] esmtool/labels: bodyPartLabel, meshPartLabel, meshTypeLabel Signed chars, unsigned chars... Just use int for index everywhere. --- apps/esmtool/labels.cpp | 18 +++++++++--------- apps/esmtool/labels.hpp | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index d7d3cf9ce..f08c31003 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -16,7 +16,7 @@ #include #include -std::string bodyPartLabel(signed char idx) +std::string bodyPartLabel(int idx) { const char *bodyPartLabels[] = { "Head", @@ -48,13 +48,13 @@ std::string bodyPartLabel(signed char idx) "Tail" }; - if ((int)idx >= 0 && (int)(idx) <= 26) - return bodyPartLabels[(int)(idx)]; + if (idx >= 0 && idx <= 26) + return bodyPartLabels[idx]; else return "Invalid"; } -std::string meshPartLabel(signed char idx) +std::string meshPartLabel(int idx) { const char *meshPartLabels[] = { "Head", @@ -74,13 +74,13 @@ std::string meshPartLabel(signed char idx) "Tail" }; - if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MP_Tail) - return meshPartLabels[(int)(idx)]; + if (idx >= 0 && idx <= ESM::BodyPart::MP_Tail) + return meshPartLabels[idx]; else return "Invalid"; } -std::string meshTypeLabel(signed char idx) +std::string meshTypeLabel(int idx) { const char *meshTypeLabels[] = { "Skin", @@ -88,8 +88,8 @@ std::string meshTypeLabel(signed char idx) "Armor" }; - if ((int)(idx) >= 0 && (int)(idx) <= ESM::BodyPart::MT_Armor) - return meshTypeLabels[(int)(idx)]; + if (idx >= 0 && idx <= ESM::BodyPart::MT_Armor) + return meshTypeLabels[idx]; else return "Invalid"; } diff --git a/apps/esmtool/labels.hpp b/apps/esmtool/labels.hpp index bf3958037..48d7b249b 100644 --- a/apps/esmtool/labels.hpp +++ b/apps/esmtool/labels.hpp @@ -3,9 +3,9 @@ #include -std::string bodyPartLabel(signed char idx); -std::string meshPartLabel(signed char idx); -std::string meshTypeLabel(signed char idx); +std::string bodyPartLabel(int idx); +std::string meshPartLabel(int idx); +std::string meshTypeLabel(int idx); std::string clothingTypeLabel(int idx); std::string armorTypeLabel(int idx); std::string dialogTypeLabel(int idx); From eb09662f1ddd67cdae0c5af2b1d96aa0ceba3d9e Mon Sep 17 00:00:00 2001 From: Douglas Mencken Date: Thu, 14 Feb 2013 04:22:00 -0500 Subject: [PATCH 634/916] Don't include boost/filesystem/v3/operations.hpp, use boost/filesystem/operations.hpp instead. It is boost headers' job to deal with their internals. --- apps/openmw/mwworld/esmstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 1666ad823..257676076 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace MWWorld { From 7d918caa9355f59cb37f38c326a5fbf9523d9604 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Feb 2013 16:26:40 +0100 Subject: [PATCH 635/916] Don't allow dialogue if player controls are disabled. --- apps/openmw/mwworld/actiontalk.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 905497f85..59b37370a 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -3,6 +3,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/inputmanager.hpp" namespace MWWorld { @@ -10,6 +11,7 @@ namespace MWWorld void ActionTalk::executeImp (const Ptr& actor) { - MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + if (MWBase::Environment::get().getInputManager ()->getControlSwitch ("playercontrols")) + MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); } } From 0bc34c1c0d7eb10fd7eb942efd23d7443be6e328 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Feb 2013 16:40:44 +0100 Subject: [PATCH 636/916] Action::executeImp returns a bool value to indicate if the sound should be played. --- apps/openmw/mwworld/action.cpp | 4 +--- apps/openmw/mwworld/action.hpp | 3 ++- apps/openmw/mwworld/actionalchemy.cpp | 3 ++- apps/openmw/mwworld/actionalchemy.hpp | 2 +- apps/openmw/mwworld/actionapply.cpp | 6 ++++-- apps/openmw/mwworld/actionapply.hpp | 4 ++-- apps/openmw/mwworld/actioneat.cpp | 4 +++- apps/openmw/mwworld/actioneat.hpp | 2 +- apps/openmw/mwworld/actionequip.cpp | 4 +++- apps/openmw/mwworld/actionequip.hpp | 2 +- apps/openmw/mwworld/actionopen.cpp | 5 +++-- apps/openmw/mwworld/actionopen.hpp | 2 +- apps/openmw/mwworld/actionread.cpp | 3 ++- apps/openmw/mwworld/actionread.hpp | 2 +- apps/openmw/mwworld/actiontake.cpp | 6 ++++-- apps/openmw/mwworld/actiontake.hpp | 2 +- apps/openmw/mwworld/actiontalk.cpp | 6 +++++- apps/openmw/mwworld/actiontalk.hpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 3 ++- apps/openmw/mwworld/actionteleport.hpp | 2 +- apps/openmw/mwworld/failedaction.cpp | 9 +++++---- apps/openmw/mwworld/failedaction.hpp | 4 ++-- apps/openmw/mwworld/nullaction.hpp | 2 +- 23 files changed, 49 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index a5199fb3e..b4897109a 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -18,7 +18,7 @@ MWWorld::Action::~Action() {} void MWWorld::Action::execute (const Ptr& actor) { - if (!mSoundId.empty()) + if (!mSoundId.empty() && executeImp (actor)) { if (mKeepSound && actor.getRefData().getHandle()=="player") { @@ -35,8 +35,6 @@ void MWWorld::Action::execute (const Ptr& actor) mKeepSound ? MWBase::SoundManager::Play_NoTrack : MWBase::SoundManager::Play_Normal); } } - - executeImp (actor); } void MWWorld::Action::setSound (const std::string& id) diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index d8e5d93bb..42c2ad084 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -18,7 +18,8 @@ namespace MWWorld Action (const Action& action); Action& operator= (const Action& action); - virtual void executeImp (const Ptr& actor) = 0; + /// @return true if the sound should be played, false if not (e.g. if the action is not allowed) + virtual bool executeImp (const Ptr& actor) = 0; protected: diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index bba75bc49..20093279e 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -5,8 +5,9 @@ namespace MWWorld { - void ActionAlchemy::executeImp (const Ptr& actor) + bool ActionAlchemy::executeImp (const Ptr& actor) { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy); + return true; } } diff --git a/apps/openmw/mwworld/actionalchemy.hpp b/apps/openmw/mwworld/actionalchemy.hpp index e6d1a7976..814f347c8 100644 --- a/apps/openmw/mwworld/actionalchemy.hpp +++ b/apps/openmw/mwworld/actionalchemy.hpp @@ -7,7 +7,7 @@ namespace MWWorld { class ActionAlchemy : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); }; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index f78b8f798..2a41b5613 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -9,9 +9,10 @@ namespace MWWorld : Action (false, target), mId (id) {} - void ActionApply::executeImp (const Ptr& actor) + bool ActionApply::executeImp (const Ptr& actor) { MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor); + return true; } @@ -20,9 +21,10 @@ namespace MWWorld : Action (false, target), mId (id), mSkillIndex (skillIndex), mUsageType (usageType) {} - void ActionApplyWithSkill::executeImp (const Ptr& actor) + bool ActionApplyWithSkill::executeImp (const Ptr& actor) { if (MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor) && mUsageType!=-1) MWWorld::Class::get (getTarget()).skillUsageSucceeded (actor, mSkillIndex, mUsageType); + return true; } } diff --git a/apps/openmw/mwworld/actionapply.hpp b/apps/openmw/mwworld/actionapply.hpp index 3353ae0ee..53b2de1d0 100644 --- a/apps/openmw/mwworld/actionapply.hpp +++ b/apps/openmw/mwworld/actionapply.hpp @@ -13,7 +13,7 @@ namespace MWWorld { std::string mId; - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: @@ -26,7 +26,7 @@ namespace MWWorld int mSkillIndex; int mUsageType; - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 63efff738..81c45f051 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -16,7 +16,7 @@ namespace MWWorld { - void ActionEat::executeImp (const Ptr& actor) + bool ActionEat::executeImp (const Ptr& actor) { // remove used item getTarget().getRefData().setCount (getTarget().getRefData().getCount()-1); @@ -42,6 +42,8 @@ namespace MWWorld // increase skill Class::get (actor).skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } + + return true; } ActionEat::ActionEat (const MWWorld::Ptr& object) : Action (false, object) {} diff --git a/apps/openmw/mwworld/actioneat.hpp b/apps/openmw/mwworld/actioneat.hpp index ce5330db7..265f5aa68 100644 --- a/apps/openmw/mwworld/actioneat.hpp +++ b/apps/openmw/mwworld/actioneat.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionEat : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 2d257aa61..902e0fdb6 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -16,7 +16,7 @@ namespace MWWorld { } - void ActionEquip::executeImp (const Ptr& actor) + bool ActionEquip::executeImp (const Ptr& actor) { MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); @@ -113,5 +113,7 @@ namespace MWWorld /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); + + return true; } } diff --git a/apps/openmw/mwworld/actionequip.hpp b/apps/openmw/mwworld/actionequip.hpp index 3b56c7402..fb3a1ac10 100644 --- a/apps/openmw/mwworld/actionequip.hpp +++ b/apps/openmw/mwworld/actionequip.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionEquip : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: /// @param item to equip diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 040a3856e..da570dff0 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -14,12 +14,13 @@ namespace MWWorld { } - void ActionOpen::executeImp (const MWWorld::Ptr& actor) + bool ActionOpen::executeImp (const MWWorld::Ptr& actor) { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return; + return false; MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget()); + return true; } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index c49ebefa5..42ad4aecb 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -10,7 +10,7 @@ namespace MWWorld { class ActionOpen : public Action { - virtual void executeImp (const MWWorld::Ptr& actor); + virtual bool executeImp (const MWWorld::Ptr& actor); public: ActionOpen (const Ptr& container); diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 6d5d9d8fd..157b051d6 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -19,7 +19,7 @@ namespace MWWorld { } - void ActionRead::executeImp (const MWWorld::Ptr& actor) + bool ActionRead::executeImp (const MWWorld::Ptr& actor) { LiveCellRef *ref = getTarget().get(); @@ -53,5 +53,6 @@ namespace MWWorld npcStats.flagAsUsed (ref->mBase->mId); } + return true; } } diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index 00a4756dd..dfb536c64 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionRead : public Action { - virtual void executeImp (const MWWorld::Ptr& actor); + virtual bool executeImp (const MWWorld::Ptr& actor); public: /// @param book or scroll to read diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index fd28dd52e..fef8a7e73 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -12,10 +12,10 @@ namespace MWWorld { ActionTake::ActionTake (const MWWorld::Ptr& object) : Action (true, object) {} - void ActionTake::executeImp (const Ptr& actor) + bool ActionTake::executeImp (const Ptr& actor) { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return; + return false; // insert into player's inventory MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPtr ("player", true); @@ -23,5 +23,7 @@ namespace MWWorld MWWorld::Class::get (player).getContainerStore (player).add (getTarget()); MWBase::Environment::get().getWorld()->deleteObject (getTarget()); + + return true; } } diff --git a/apps/openmw/mwworld/actiontake.hpp b/apps/openmw/mwworld/actiontake.hpp index b0a9b8247..2a87156d0 100644 --- a/apps/openmw/mwworld/actiontake.hpp +++ b/apps/openmw/mwworld/actiontake.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionTake : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 59b37370a..36c54f00e 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -9,9 +9,13 @@ namespace MWWorld { ActionTalk::ActionTalk (const Ptr& actor) : Action (false, actor) {} - void ActionTalk::executeImp (const Ptr& actor) + bool ActionTalk::executeImp (const Ptr& actor) { if (MWBase::Environment::get().getInputManager ()->getControlSwitch ("playercontrols")) + { MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + return true; + } + return false; } } diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp index b88b168d8..91c71dc79 100644 --- a/apps/openmw/mwworld/actiontalk.hpp +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionTalk : public Action { - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index ae5ffc3b9..9b21cc876 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -12,11 +12,12 @@ namespace MWWorld { } - void ActionTeleport::executeImp (const Ptr& actor) + bool ActionTeleport::executeImp (const Ptr& actor) { if (mCellName.empty()) MWBase::Environment::get().getWorld()->changeToExteriorCell (mPosition); else MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, mPosition); + return true; } } diff --git a/apps/openmw/mwworld/actionteleport.hpp b/apps/openmw/mwworld/actionteleport.hpp index a13cb61b2..4f771cac9 100644 --- a/apps/openmw/mwworld/actionteleport.hpp +++ b/apps/openmw/mwworld/actionteleport.hpp @@ -14,7 +14,7 @@ namespace MWWorld std::string mCellName; ESM::Position mPosition; - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index ec763dba0..7ce27f76f 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -11,11 +11,12 @@ namespace MWWorld { } - void FailedAction::executeImp (const Ptr& actor) + bool FailedAction::executeImp (const Ptr& actor) { if ( actor.getRefData().getHandle()=="player" && !(message.empty())) - { - MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); - } + { + MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); + } + return false; } } diff --git a/apps/openmw/mwworld/failedaction.hpp b/apps/openmw/mwworld/failedaction.hpp index e736bfb63..7d64afe74 100644 --- a/apps/openmw/mwworld/failedaction.hpp +++ b/apps/openmw/mwworld/failedaction.hpp @@ -10,11 +10,11 @@ namespace MWWorld { std::string message; - virtual void executeImp (const Ptr& actor); + virtual bool executeImp (const Ptr& actor); public: FailedAction (const std::string& message = std::string()); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwworld/nullaction.hpp b/apps/openmw/mwworld/nullaction.hpp index 7ef8b4a06..f5544e4c1 100644 --- a/apps/openmw/mwworld/nullaction.hpp +++ b/apps/openmw/mwworld/nullaction.hpp @@ -8,7 +8,7 @@ namespace MWWorld /// \brief Action: do nothing class NullAction : public Action { - virtual void executeImp (const Ptr& actor) {} + virtual bool executeImp (const Ptr& actor) {return false;} }; } From a5c8d5748f990025ef7a3dd3eb5bb5d291fe9703 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Feb 2013 18:05:25 +0100 Subject: [PATCH 637/916] fix FailedAction. --- apps/openmw/mwworld/failedaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index 7ce27f76f..e2ca78b2c 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -17,6 +17,6 @@ namespace MWWorld { MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); } - return false; + return true; } } From f0220fb06b099dd48aa4c3825135fabecb9cd400 Mon Sep 17 00:00:00 2001 From: Wareya Date: Sat, 16 Feb 2013 13:35:03 -0500 Subject: [PATCH 638/916] Implement "Rest Until Healed" Fixes: https://bugs.openmw.org/issues/563 --- apps/openmw/mwgui/waitdialog.cpp | 62 ++++++++++++++++++++++++++++---- apps/openmw/mwgui/waitdialog.hpp | 3 +- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 4f2c98c08..2953ca58d 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,5 +1,8 @@ #include "waitdialog.hpp" +#include +#include + #include #include @@ -14,6 +17,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" #include "widgets.hpp" @@ -132,21 +136,66 @@ namespace MWGui void WaitDialog::onUntilHealedButtonClicked(MyGUI::Widget* sender) { - startWaiting(); + // we need to sleep for a specific time, and since that isn't calculated yet, we'll do it here + // I'm making the assumption here that the # of hours rested is calculated when rest is started + // TODO: the rougher logic here (calculating the hourly deltas) should really go into helper funcs elsewhere + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::CreatureStats stats = MWWorld::Class::get(player).getCreatureStats(player); + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + + float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; + + bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(136)).mMagnitude > 0); + float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); + float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); + + // this massive duplication is why it has to be put into helper functions instead + float fFatigueReturnBase = store.get().find("fFatigueReturnBase")->getFloat(); + float fFatigueReturnMult = store.get().find("fFatigueReturnMult")->getFloat(); + float fEndFatigueMult = store.get().find("fEndFatigueMult")->getFloat(); + float capacity = MWWorld::Class::get(player).getCapacity(player); + float encumbrance = MWWorld::Class::get(player).getEncumbrance(player); + float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity); + if (normalizedEncumbrance > 1) + normalizedEncumbrance = 1; + float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); + hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified(); + + std::cout << "Calced health per hour: " << hourlyHealthDelta << std::endl; + + float healthHours = hourlyHealthDelta >= 0.0 + ? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta + : 1.0f; + std::cout << "Calced health hours: " << healthHours << std::endl; + std::cout << "getBase returns " << stats.getHealth().getBase() << ", getModified() returns " << stats.getHealth().getModified() << std::endl; + float magickaHours = stunted ? 0.0 : + hourlyMagickaDelta >= 0.0 + ? (stats.getMagicka().getBase() - stats.getMagicka().getCurrent()) / hourlyMagickaDelta + : 1.0f; + float fatigueHours = hourlyFatigueDelta >= 0.0 + ? (stats.getFatigue().getBase() - stats.getFatigue().getCurrent()) / hourlyFatigueDelta + : 1.0f; + + int autoHours = int(std::ceil( std::max(std::max(healthHours, magickaHours), std::max(fatigueHours, 1.0f)) )); // this should use a variadic max if possible + + startWaiting(autoHours); } void WaitDialog::onWaitButtonClicked(MyGUI::Widget* sender) { - startWaiting(); + startWaiting(mManualHours); } - void WaitDialog::startWaiting () + void WaitDialog::startWaiting(int hoursToWait) { MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2); setVisible(false); mProgressBar.setVisible (true); + mWaiting = true; mCurHour = 0; + mHours = hoursToWait; + mRemainingTime = 0.05; mProgressBar.setProgress (0, mHours); } @@ -159,7 +208,7 @@ namespace MWGui void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) { mHourText->setCaptionWithReplacing (boost::lexical_cast(position+1) + " #{sRestMenu2}"); - mHours = position+1; + mManualHours = position+1; } void WaitDialog::setCanRest (bool canRest) @@ -181,9 +230,9 @@ namespace MWGui mRemainingTime -= dt; - if (mRemainingTime < 0) + while (mRemainingTime < 0) { - mRemainingTime = 0.05; + mRemainingTime += 0.05; ++mCurHour; mProgressBar.setProgress (mCurHour, mHours); @@ -197,6 +246,7 @@ namespace MWGui if (mCurHour > mHours) stopWaiting(); + } void WaitDialog::stopWaiting () diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 6af565c6e..c102d0fc6 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -47,6 +47,7 @@ namespace MWGui bool mSleeping; int mCurHour; int mHours; + int mManualHours; // stores the hours to rest selected via slider float mRemainingTime; WaitDialogProgressBar mProgressBar; @@ -58,7 +59,7 @@ namespace MWGui void setCanRest(bool canRest); - void startWaiting(); + void startWaiting(int hoursToWait); void stopWaiting(); }; From c98a81558151092542bc4882fb6a6ded4dcaddb0 Mon Sep 17 00:00:00 2001 From: Wareya Date: Sat, 16 Feb 2013 13:37:25 -0500 Subject: [PATCH 639/916] Remove debug printing from previous commit --- apps/openmw/mwgui/waitdialog.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 2953ca58d..2c74dd2fd 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,6 +1,5 @@ #include "waitdialog.hpp" -#include #include #include @@ -160,14 +159,10 @@ namespace MWGui normalizedEncumbrance = 1; float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified(); - - std::cout << "Calced health per hour: " << hourlyHealthDelta << std::endl; float healthHours = hourlyHealthDelta >= 0.0 ? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta - : 1.0f; - std::cout << "Calced health hours: " << healthHours << std::endl; - std::cout << "getBase returns " << stats.getHealth().getBase() << ", getModified() returns " << stats.getHealth().getModified() << std::endl; + : 1.0f; float magickaHours = stunted ? 0.0 : hourlyMagickaDelta >= 0.0 ? (stats.getMagicka().getBase() - stats.getMagicka().getCurrent()) / hourlyMagickaDelta From df8e502f8c5139a850fa74cc2ff53f3804fb970c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 02:52:49 +0100 Subject: [PATCH 640/916] Ouch, I used && instead of &, this broke actions without a sound --- apps/openmw/mwworld/action.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index b4897109a..0d50d8ded 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -18,7 +18,7 @@ MWWorld::Action::~Action() {} void MWWorld::Action::execute (const Ptr& actor) { - if (!mSoundId.empty() && executeImp (actor)) + if (!mSoundId.empty() & executeImp (actor)) { if (mKeepSound && actor.getRefData().getHandle()=="player") { From 373de19aeec752958a37e9fe0f120ef95493ab1d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 03:02:47 +0100 Subject: [PATCH 641/916] Removed dialogue fix again, now on separate branch --- apps/openmw/mwworld/actiontalk.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 36c54f00e..6bee9eb26 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -11,11 +11,7 @@ namespace MWWorld bool ActionTalk::executeImp (const Ptr& actor) { - if (MWBase::Environment::get().getInputManager ()->getControlSwitch ("playercontrols")) - { - MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); - return true; - } - return false; + MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); + return true; } } From c4f17f5596efde3267c802f1463a0b822d97f70a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 03:03:41 +0100 Subject: [PATCH 642/916] playercontrols switch now disables activation in general (Chris' suggestion) --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 02a699ece..296ff3cc7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -642,7 +642,8 @@ namespace MWInput void InputManager::activate() { - mEngine.activate(); + if (mControlSwitch["playercontrols"]) + mEngine.activate(); } void InputManager::toggleAutoMove() From ceefae81e8ea34fdafc2682b2f6a777d65b02587 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sun, 17 Feb 2013 07:46:50 -0600 Subject: [PATCH 643/916] fix for the opencs icon --- apps/opencs/CMakeLists.txt | 6 +++--- apps/opencs/main.cpp | 6 +++++- files/opencs/opencs.png | Bin 0 -> 65168 bytes files/opencs/resources.qrc | 5 +++++ 4 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 files/opencs/opencs.png create mode 100644 files/opencs/resources.qrc diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d1cfbea52..af8fb5981 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -40,7 +40,7 @@ opencs_units_noqt (model/tools opencs_units (view/doc - viewmanager view operations operation subview + viewmanager view operations operation subview startup ) opencs_units_noqt (view/doc @@ -73,7 +73,7 @@ opencs_units_noqt (view/tools set (OPENCS_US ) -set (OPENCS_RES +set (OPENCS_RES ../../files/opencs/resources.qrc ) source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) @@ -102,4 +102,4 @@ target_link_libraries(opencs ${Boost_LIBRARIES} ${QT_LIBRARIES} components -) \ No newline at end of file +) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index 4b1a688c2..aa315804b 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -5,6 +5,7 @@ #include #include +#include class Application : public QApplication { @@ -31,9 +32,12 @@ class Application : public QApplication int main(int argc, char *argv[]) { + Q_INIT_RESOURCE (resources); Application mApplication (argc, argv); + mApplication.setWindowIcon (QIcon (":./opencs.png")); + CS::Editor editor; return editor.run(); -} \ No newline at end of file +} diff --git a/files/opencs/opencs.png b/files/opencs/opencs.png new file mode 100644 index 0000000000000000000000000000000000000000..dddf220a3cbd0df1f4437ce4e00a95aef4b0e4a9 GIT binary patch literal 65168 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 + + opencs.png + + From 6356d3a385c7f1a1df5ce25267021f4d6833be45 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 17 Feb 2013 06:02:57 -0800 Subject: [PATCH 644/916] Start actors with collision enabled NPCs are now affected by gravity. The player still starts in no-collision mode though, since they start in the void rather than a door marker. --- libs/openengine/bullet/physic.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 2b26c3a48..7ffe07189 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -29,8 +29,11 @@ namespace Physic PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) - , mBody(0), onGround(false), collisionMode(false), mBoxRotation(0,0,0,0), verticalForce(0.0f) + , mBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) { + // FIXME: Force player to start in no-collision mode for now, until he spawns at a proper door marker. + if(name == "player") + collisionMode = false; mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); From 00db13be32d0ec107541e3427934117e900fb152 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 15:56:22 +0100 Subject: [PATCH 645/916] Reverted previous commits, and handle disallowed inventory in MWWorld::Class. Wanted to avoid this, but the previous solution broke teleport door sounds. Also fixed book/scroll window take button showing when inventory was not allowed. --- apps/openmw/mwclass/apparatus.cpp | 4 ++++ apps/openmw/mwclass/armor.cpp | 4 ++++ apps/openmw/mwclass/clothing.cpp | 4 ++++ apps/openmw/mwclass/container.cpp | 4 ++++ apps/openmw/mwclass/ingredient.cpp | 4 ++++ apps/openmw/mwclass/light.cpp | 3 +++ apps/openmw/mwclass/lockpick.cpp | 4 ++++ apps/openmw/mwclass/misc.cpp | 4 ++++ apps/openmw/mwclass/potion.cpp | 4 ++++ apps/openmw/mwclass/probe.cpp | 4 ++++ apps/openmw/mwclass/repair.cpp | 4 ++++ apps/openmw/mwclass/weapon.cpp | 4 ++++ apps/openmw/mwgui/bookwindow.cpp | 15 ++++++++++++--- apps/openmw/mwgui/bookwindow.hpp | 5 +++++ apps/openmw/mwgui/scrollwindow.cpp | 15 ++++++++++++--- apps/openmw/mwgui/scrollwindow.hpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++++++++++++++- apps/openmw/mwworld/action.cpp | 4 +++- apps/openmw/mwworld/action.hpp | 3 +-- apps/openmw/mwworld/actionalchemy.cpp | 3 +-- apps/openmw/mwworld/actionalchemy.hpp | 2 +- apps/openmw/mwworld/actionapply.cpp | 6 ++---- apps/openmw/mwworld/actionapply.hpp | 4 ++-- apps/openmw/mwworld/actioneat.cpp | 4 +--- apps/openmw/mwworld/actioneat.hpp | 2 +- apps/openmw/mwworld/actionequip.cpp | 4 +--- apps/openmw/mwworld/actionequip.hpp | 2 +- apps/openmw/mwworld/actionopen.cpp | 5 ++--- apps/openmw/mwworld/actionopen.hpp | 2 +- apps/openmw/mwworld/actionread.cpp | 3 +-- apps/openmw/mwworld/actionread.hpp | 2 +- apps/openmw/mwworld/actiontake.cpp | 7 +------ apps/openmw/mwworld/actiontake.hpp | 2 +- apps/openmw/mwworld/actiontalk.cpp | 4 +--- apps/openmw/mwworld/actiontalk.hpp | 2 +- apps/openmw/mwworld/actionteleport.cpp | 3 +-- apps/openmw/mwworld/actionteleport.hpp | 2 +- apps/openmw/mwworld/failedaction.cpp | 9 ++++----- apps/openmw/mwworld/failedaction.hpp | 4 ++-- apps/openmw/mwworld/nullaction.hpp | 2 +- 40 files changed, 127 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 06467bb21..2c561eb85 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -12,6 +12,7 @@ #include "../mwworld/actionalchemy.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -61,6 +62,9 @@ namespace MWClass boost::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action( new MWWorld::ActionTake (ptr)); diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 704173b1c..654cb87fd 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -15,6 +15,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -64,6 +65,9 @@ namespace MWClass boost::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index c411bb193..892ac091c 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index bbe005955..a2d75131e 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/failedaction.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/cellstore.hpp" @@ -85,6 +86,9 @@ namespace MWClass boost::shared_ptr Container::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + const std::string lockedSound = "LockedChest"; const std::string trapActivationSound = "Disarm Trap Fail"; diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 7ad8f1b47..bbba45df5 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -13,6 +13,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwworld/actioneat.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwmechanics/npcstats.hpp" @@ -72,6 +73,9 @@ namespace MWClass boost::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index b94b0d395..235e57d37 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -88,6 +88,9 @@ namespace MWClass boost::shared_ptr Light::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index a667fefb2..7e909437c 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index a21cc2aef..d43a44359 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -65,6 +66,9 @@ namespace MWClass boost::shared_ptr Miscellaneous::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 09d152de7..c3a6df211 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -13,6 +13,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action( new MWWorld::ActionTake (ptr)); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 0d8653aa8..a28be17e7 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -61,6 +62,9 @@ namespace MWClass boost::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index edb28d16c..39a7f65e0 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -11,6 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -60,6 +61,9 @@ namespace MWClass boost::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index c8fe0d276..d8c11558c 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -13,6 +13,7 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/nullaction.hpp" #include "../mwgui/tooltips.hpp" @@ -62,6 +63,9 @@ namespace MWClass boost::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { + if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) + return boost::shared_ptr (new MWWorld::NullAction ()); + boost::shared_ptr action(new MWWorld::ActionTake (ptr)); action->setSound(getUpSoundId(ptr)); diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 659795e18..777751069 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -14,8 +14,10 @@ using namespace MWGui; -BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_book.layout", parWindowManager) +BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_book.layout", parWindowManager) + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); @@ -85,7 +87,14 @@ void BookWindow::open (MWWorld::Ptr book) void BookWindow::setTakeButtonShow(bool show) { - mTakeButton->setVisible(show); + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); +} + +void BookWindow::setInventoryAllowed(bool allowed) +{ + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 5887975ea..a509f131f 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -17,6 +17,8 @@ namespace MWGui void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); + void setInventoryAllowed(bool allowed); + protected: void onNextPageButtonClicked (MyGUI::Widget* sender); void onPrevPageButtonClicked (MyGUI::Widget* sender); @@ -40,6 +42,9 @@ namespace MWGui std::vector mPages; MWWorld::Ptr mBook; + + bool mTakeButtonShow; + bool mTakeButtonAllowed; }; } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 8317025e0..3bd3a4743 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,8 +12,10 @@ using namespace MWGui; -ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_scroll.layout", parWindowManager) +ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_scroll.layout", parWindowManager) + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { getWidget(mTextView, "TextView"); @@ -50,7 +52,14 @@ void ScrollWindow::open (MWWorld::Ptr scroll) void ScrollWindow::setTakeButtonShow(bool show) { - mTakeButton->setVisible(show); + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); +} + +void ScrollWindow::setInventoryAllowed(bool allowed) +{ + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); } void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 7932a215b..42b6395a9 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -15,6 +15,7 @@ namespace MWGui void open (MWWorld::Ptr scroll); void setTakeButtonShow(bool show); + void setInventoryAllowed(bool allowed); protected: void onCloseButtonClicked (MyGUI::Widget* _sender); @@ -26,6 +27,10 @@ namespace MWGui MyGUI::ScrollView* mTextView; MWWorld::Ptr mScroll; + + bool mTakeButtonShow; + bool mTakeButtonAllowed; + }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e360aad19..e03b91216 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -109,7 +109,6 @@ WindowManager::WindowManager( , mHudEnabled(true) , mTranslationDataStorage (translationDataStorage) { - // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); mGui = mGuiManager->getGui(); @@ -196,6 +195,9 @@ WindowManager::WindowManager( unsetSelectedSpell(); unsetSelectedWeapon(); + if (newGame) + disallowAll (); + // Set up visibility updateVisible(); } @@ -943,12 +945,23 @@ bool WindowManager::isAllowed (GuiWindow wnd) const void WindowManager::allow (GuiWindow wnd) { mAllowed = (GuiWindow)(mAllowed | wnd); + + if (wnd & GW_Inventory) + { + mBookWindow->setInventoryAllowed (true); + mScrollWindow->setInventoryAllowed (true); + } + updateVisible(); } void WindowManager::disallowAll() { mAllowed = GW_None; + + mBookWindow->setInventoryAllowed (false); + mScrollWindow->setInventoryAllowed (false); + updateVisible(); } diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 0d50d8ded..a5199fb3e 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -18,7 +18,7 @@ MWWorld::Action::~Action() {} void MWWorld::Action::execute (const Ptr& actor) { - if (!mSoundId.empty() & executeImp (actor)) + if (!mSoundId.empty()) { if (mKeepSound && actor.getRefData().getHandle()=="player") { @@ -35,6 +35,8 @@ void MWWorld::Action::execute (const Ptr& actor) mKeepSound ? MWBase::SoundManager::Play_NoTrack : MWBase::SoundManager::Play_Normal); } } + + executeImp (actor); } void MWWorld::Action::setSound (const std::string& id) diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index 42c2ad084..d8e5d93bb 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -18,8 +18,7 @@ namespace MWWorld Action (const Action& action); Action& operator= (const Action& action); - /// @return true if the sound should be played, false if not (e.g. if the action is not allowed) - virtual bool executeImp (const Ptr& actor) = 0; + virtual void executeImp (const Ptr& actor) = 0; protected: diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index 20093279e..bba75bc49 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -5,9 +5,8 @@ namespace MWWorld { - bool ActionAlchemy::executeImp (const Ptr& actor) + void ActionAlchemy::executeImp (const Ptr& actor) { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy); - return true; } } diff --git a/apps/openmw/mwworld/actionalchemy.hpp b/apps/openmw/mwworld/actionalchemy.hpp index 814f347c8..e6d1a7976 100644 --- a/apps/openmw/mwworld/actionalchemy.hpp +++ b/apps/openmw/mwworld/actionalchemy.hpp @@ -7,7 +7,7 @@ namespace MWWorld { class ActionAlchemy : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); }; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 2a41b5613..f78b8f798 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -9,10 +9,9 @@ namespace MWWorld : Action (false, target), mId (id) {} - bool ActionApply::executeImp (const Ptr& actor) + void ActionApply::executeImp (const Ptr& actor) { MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor); - return true; } @@ -21,10 +20,9 @@ namespace MWWorld : Action (false, target), mId (id), mSkillIndex (skillIndex), mUsageType (usageType) {} - bool ActionApplyWithSkill::executeImp (const Ptr& actor) + void ActionApplyWithSkill::executeImp (const Ptr& actor) { if (MWWorld::Class::get (getTarget()).apply (getTarget(), mId, actor) && mUsageType!=-1) MWWorld::Class::get (getTarget()).skillUsageSucceeded (actor, mSkillIndex, mUsageType); - return true; } } diff --git a/apps/openmw/mwworld/actionapply.hpp b/apps/openmw/mwworld/actionapply.hpp index 53b2de1d0..3353ae0ee 100644 --- a/apps/openmw/mwworld/actionapply.hpp +++ b/apps/openmw/mwworld/actionapply.hpp @@ -13,7 +13,7 @@ namespace MWWorld { std::string mId; - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: @@ -26,7 +26,7 @@ namespace MWWorld int mSkillIndex; int mUsageType; - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 81c45f051..63efff738 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -16,7 +16,7 @@ namespace MWWorld { - bool ActionEat::executeImp (const Ptr& actor) + void ActionEat::executeImp (const Ptr& actor) { // remove used item getTarget().getRefData().setCount (getTarget().getRefData().getCount()-1); @@ -42,8 +42,6 @@ namespace MWWorld // increase skill Class::get (actor).skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } - - return true; } ActionEat::ActionEat (const MWWorld::Ptr& object) : Action (false, object) {} diff --git a/apps/openmw/mwworld/actioneat.hpp b/apps/openmw/mwworld/actioneat.hpp index 265f5aa68..ce5330db7 100644 --- a/apps/openmw/mwworld/actioneat.hpp +++ b/apps/openmw/mwworld/actioneat.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionEat : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 902e0fdb6..2d257aa61 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -16,7 +16,7 @@ namespace MWWorld { } - bool ActionEquip::executeImp (const Ptr& actor) + void ActionEquip::executeImp (const Ptr& actor) { MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); @@ -113,7 +113,5 @@ namespace MWWorld /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); - - return true; } } diff --git a/apps/openmw/mwworld/actionequip.hpp b/apps/openmw/mwworld/actionequip.hpp index fb3a1ac10..3b56c7402 100644 --- a/apps/openmw/mwworld/actionequip.hpp +++ b/apps/openmw/mwworld/actionequip.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionEquip : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: /// @param item to equip diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index da570dff0..040a3856e 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -14,13 +14,12 @@ namespace MWWorld { } - bool ActionOpen::executeImp (const MWWorld::Ptr& actor) + void ActionOpen::executeImp (const MWWorld::Ptr& actor) { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return false; + return; MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget()); - return true; } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index 42ad4aecb..c49ebefa5 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -10,7 +10,7 @@ namespace MWWorld { class ActionOpen : public Action { - virtual bool executeImp (const MWWorld::Ptr& actor); + virtual void executeImp (const MWWorld::Ptr& actor); public: ActionOpen (const Ptr& container); diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 157b051d6..6d5d9d8fd 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -19,7 +19,7 @@ namespace MWWorld { } - bool ActionRead::executeImp (const MWWorld::Ptr& actor) + void ActionRead::executeImp (const MWWorld::Ptr& actor) { LiveCellRef *ref = getTarget().get(); @@ -53,6 +53,5 @@ namespace MWWorld npcStats.flagAsUsed (ref->mBase->mId); } - return true; } } diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index dfb536c64..00a4756dd 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionRead : public Action { - virtual bool executeImp (const MWWorld::Ptr& actor); + virtual void executeImp (const MWWorld::Ptr& actor); public: /// @param book or scroll to read diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index fef8a7e73..cdd19b46e 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -12,18 +12,13 @@ namespace MWWorld { ActionTake::ActionTake (const MWWorld::Ptr& object) : Action (true, object) {} - bool ActionTake::executeImp (const Ptr& actor) + void ActionTake::executeImp (const Ptr& actor) { - if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) - return false; - // insert into player's inventory MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPtr ("player", true); MWWorld::Class::get (player).getContainerStore (player).add (getTarget()); MWBase::Environment::get().getWorld()->deleteObject (getTarget()); - - return true; } } diff --git a/apps/openmw/mwworld/actiontake.hpp b/apps/openmw/mwworld/actiontake.hpp index 2a87156d0..b0a9b8247 100644 --- a/apps/openmw/mwworld/actiontake.hpp +++ b/apps/openmw/mwworld/actiontake.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionTake : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index 6bee9eb26..905497f85 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -3,15 +3,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwbase/inputmanager.hpp" namespace MWWorld { ActionTalk::ActionTalk (const Ptr& actor) : Action (false, actor) {} - bool ActionTalk::executeImp (const Ptr& actor) + void ActionTalk::executeImp (const Ptr& actor) { MWBase::Environment::get().getDialogueManager()->startDialogue (getTarget()); - return true; } } diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp index 91c71dc79..b88b168d8 100644 --- a/apps/openmw/mwworld/actiontalk.hpp +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -8,7 +8,7 @@ namespace MWWorld { class ActionTalk : public Action { - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 9b21cc876..ae5ffc3b9 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -12,12 +12,11 @@ namespace MWWorld { } - bool ActionTeleport::executeImp (const Ptr& actor) + void ActionTeleport::executeImp (const Ptr& actor) { if (mCellName.empty()) MWBase::Environment::get().getWorld()->changeToExteriorCell (mPosition); else MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, mPosition); - return true; } } diff --git a/apps/openmw/mwworld/actionteleport.hpp b/apps/openmw/mwworld/actionteleport.hpp index 4f771cac9..a13cb61b2 100644 --- a/apps/openmw/mwworld/actionteleport.hpp +++ b/apps/openmw/mwworld/actionteleport.hpp @@ -14,7 +14,7 @@ namespace MWWorld std::string mCellName; ESM::Position mPosition; - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index e2ca78b2c..ec763dba0 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -11,12 +11,11 @@ namespace MWWorld { } - bool FailedAction::executeImp (const Ptr& actor) + void FailedAction::executeImp (const Ptr& actor) { if ( actor.getRefData().getHandle()=="player" && !(message.empty())) - { - MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); - } - return true; + { + MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); + } } } diff --git a/apps/openmw/mwworld/failedaction.hpp b/apps/openmw/mwworld/failedaction.hpp index 7d64afe74..e736bfb63 100644 --- a/apps/openmw/mwworld/failedaction.hpp +++ b/apps/openmw/mwworld/failedaction.hpp @@ -10,11 +10,11 @@ namespace MWWorld { std::string message; - virtual bool executeImp (const Ptr& actor); + virtual void executeImp (const Ptr& actor); public: FailedAction (const std::string& message = std::string()); }; } -#endif +#endif \ No newline at end of file diff --git a/apps/openmw/mwworld/nullaction.hpp b/apps/openmw/mwworld/nullaction.hpp index f5544e4c1..7ef8b4a06 100644 --- a/apps/openmw/mwworld/nullaction.hpp +++ b/apps/openmw/mwworld/nullaction.hpp @@ -8,7 +8,7 @@ namespace MWWorld /// \brief Action: do nothing class NullAction : public Action { - virtual bool executeImp (const Ptr& actor) {return false;} + virtual void executeImp (const Ptr& actor) {} }; } From d899f334444665ef073ac3d6f77623000f7831d9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 16:00:31 +0100 Subject: [PATCH 646/916] Race/Class/Birth dialogs: immediately enable OK buttons since they have a preselected entry now. --- apps/openmw/mwgui/birth.cpp | 3 --- apps/openmw/mwgui/class.cpp | 3 --- apps/openmw/mwgui/race.cpp | 3 --- 3 files changed, 9 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 99d6605d3..c53a68cf4 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -48,7 +48,6 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); - okButton->setEnabled(false); updateBirths(); updateSpells(); @@ -85,7 +84,6 @@ void BirthDialog::setBirthId(const std::string &birthId) mBirthList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -114,7 +112,6 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *birthId = mBirthList->getItemDataAt(_index); if (boost::iequals(mCurrentBirthId, *birthId)) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 475efaab3..2eed21a52 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -104,7 +104,6 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); - okButton->setEnabled(false); updateClasses(); updateStats(); @@ -140,7 +139,6 @@ void PickClassDialog::setClassId(const std::string &classId) mClassList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -169,7 +167,6 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *classId = mClassList->getItemDataAt(_index); if (boost::iequals(mCurrentClassId, *classId)) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index df6c99340..054cce7b8 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -81,7 +81,6 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); - okButton->setEnabled(false); updateRaces(); updateSkills(); @@ -135,7 +134,6 @@ void RaceDialog::setRaceId(const std::string &raceId) mRaceList->setIndexSelected(i); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); break; } } @@ -258,7 +256,6 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); - okButton->setEnabled(true); const std::string *raceId = mRaceList->getItemDataAt(_index); if (boost::iequals(mCurrentRaceId, *raceId)) return; From 5a11ddc485db96390d2bce1e07460ac3def4ff68 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 16:01:36 +0100 Subject: [PATCH 647/916] Pressing F1 again hides the quick keys menu. --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 02a699ece..b065b7f7f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -638,6 +638,8 @@ namespace MWInput { if (!mWindows.isGuiMode ()) mWindows.pushGuiMode (MWGui::GM_QuickKeysMenu); + else if (mWindows.getMode () == MWGui::GM_QuickKeysMenu) + mWindows.removeGuiMode (MWGui::GM_QuickKeysMenu); } void InputManager::activate() From 7ffcfa36220cd3a53e168e12abab8b0afdeb6b8d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 16:23:55 +0100 Subject: [PATCH 648/916] Water and clouds no longer depend on timescale. --- apps/openmw/mwrender/renderingmanager.cpp | 2 -- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwrender/water.cpp | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ce48284e0..fe8f3e99b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -353,8 +353,6 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(0.f); return; } - Ogre::ControllerManager::getSingleton().setTimeFactor( - MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); mPlayer->update(duration); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index ce8d82632..be989724a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -361,7 +361,7 @@ void SkyManager::update(float duration) mRootNode->setPosition(mCamera->getDerivedPosition()); // UV Scroll the clouds - mCloudAnimationTimer += duration * mCloudSpeed * (MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); + mCloudAnimationTimer += duration * mCloudSpeed; sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", sh::makeProperty(new sh::FloatValue(mCloudAnimationTimer))); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 3b8705ac5..33159024e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -399,7 +399,7 @@ void Water::update(float dt, Ogre::Vector3 player) mUnderwaterDome->setPosition (pos); */ - mWaterTimer += dt / 30.0 * MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + mWaterTimer += dt; sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); From 50d61a5b6e057c194f4fddb4d12ee910e1295cda Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Feb 2013 17:27:25 +0100 Subject: [PATCH 649/916] proper implementation of gmst type column --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 5 +- apps/opencs/view/doc/viewmanager.cpp | 5 + apps/opencs/view/world/enumdelegate.cpp | 101 ++++++++++++++++++++ apps/opencs/view/world/enumdelegate.hpp | 57 ++++++++++++ apps/opencs/view/world/util.cpp | 25 ++++- apps/opencs/view/world/util.hpp | 12 ++- apps/opencs/view/world/vartypedelegate.cpp | 103 +++++++++++++++++++++ apps/opencs/view/world/vartypedelegate.hpp | 38 ++++++++ 10 files changed, 342 insertions(+), 9 deletions(-) create mode 100644 apps/opencs/view/world/enumdelegate.cpp create mode 100644 apps/opencs/view/world/enumdelegate.hpp create mode 100644 apps/opencs/view/world/vartypedelegate.cpp create mode 100644 apps/opencs/view/world/vartypedelegate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8cee3f0f4..083aa9630 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -59,7 +59,7 @@ opencs_units (view/world ) opencs_units_noqt (view/world - dialoguesubview util subviews + dialoguesubview util subviews enumdelegate vartypedelegate ) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index f1871a6a9..40581972e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -29,7 +29,8 @@ namespace CSMWorld Display_String, Display_Integer, Display_Float, - Display_Var + Display_Var, + Display_VarType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index cfbd804a5..2d81a24e9 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -79,7 +79,7 @@ namespace CSMWorld int mType; FixedRecordTypeColumn (int type) - : Column ("Type", ColumnBase::Display_Integer, 0), mType (type) {} + : Column ("Record Type", ColumnBase::Display_Integer, 0), mType (type) {} virtual QVariant get (const Record& record) const { @@ -92,10 +92,11 @@ namespace CSMWorld } }; + /// \attention A var type column must be immediately followed by a suitable value column. template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_Integer) {} + VarTypeColumn() : Column ("Type", ColumnBase::Display_VarType) {} virtual QVariant get (const Record& record) const { diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 2a6309da1..473049999 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -7,6 +7,8 @@ #include "../../model/doc/document.hpp" #include "../world/util.hpp" +#include "../world/enumdelegate.hpp" +#include "../world/vartypedelegate.hpp" #include "view.hpp" @@ -32,6 +34,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType, + new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float)); } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp new file mode 100644 index 000000000..7a8b45373 --- /dev/null +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -0,0 +1,101 @@ + +#include "enumdelegate.hpp" + +#include + +#include +#include +#include + +#include "../../model/world/commands.hpp" + +void CSVWorld::EnumDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + if (QComboBox *comboBox = dynamic_cast (editor)) + { + QString value = comboBox->currentText(); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + if (iter->second==value) + { + addCommands (model, index, iter->first); + break; + } + } +} + +void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const +{ + getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); +} + + +CSVWorld::EnumDelegate::EnumDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent) +: CommandDelegate (undoStack, parent), mValues (values) +{ + +} + +QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QComboBox *comboBox = new QComboBox (parent); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + comboBox->addItem (iter->second); + + return comboBox; +} + +void CSVWorld::EnumDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const +{ + if (QComboBox *comboBox = dynamic_cast (editor)) + { + int value = index.data (Qt::EditRole).toInt(); + + std::size_t size = mValues.size(); + + for (std::size_t i=0; isetCurrentIndex (i); + break; + } + } +} + +void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + QStyleOptionViewItemV4 option2 (option); + + int value = index.data().toInt(); + + for (std::vector >::const_iterator iter (mValues.begin()); + iter!=mValues.end(); ++iter) + if (iter->first==value) + { + option2.text = iter->second; + + QApplication::style()->drawControl (QStyle::CE_ItemViewItem, &option2, painter); + + break; + } +} + + +CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new EnumDelegate (mValues, undoStack, parent); +} + +void CSVWorld::EnumDelegateFactory::add (int value, const QString& name) +{ + mValues.push_back (std::make_pair (value, name)); +} diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp new file mode 100644 index 000000000..f11252371 --- /dev/null +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -0,0 +1,57 @@ +#ifndef CSV_WORLD_ENUMDELEGATE_H +#define CSV_WORLD_ENUMDELEGATE_H + +#include + +#include + +#include + +#include "util.hpp" + +namespace CSVWorld +{ + /// \brief Integer value that represents an enum and is interacted with via a combobox + class EnumDelegate : public CommandDelegate + { + std::vector > mValues; + + private: + + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; + + virtual void addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const; + + public: + + EnumDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent); + + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + virtual void setEditorData (QWidget *editor, const QModelIndex& index) const; + + virtual void paint (QPainter *painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + }; + + class EnumDelegateFactory : public CommandDelegateFactory + { + std::vector > mValues; + + public: + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + void add (int value, const QString& name); + }; + + +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 85fda2dad..5ada1d84f 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -88,6 +88,19 @@ const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFacto } +QUndoStack& CSVWorld::CommandDelegate::getUndoStack() const +{ + return mUndoStack; +} + +void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const +{ + NastyTableModelHack hack (*model); + QStyledItemDelegate::setModelData (editor, &hack, index); + mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); +} + CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) : QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) {} @@ -97,14 +110,18 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode { if (!mEditLock) { - NastyTableModelHack hack (*model); - QStyledItemDelegate::setModelData (editor, &hack, index); - mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, hack.getData())); + setModelDataImp (editor, model, index); } + ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. } -void CSVWorld::CommandDelegate::setEditLock (bool locked) +void CSVWorld::CommandDelegate::setEditLock (bool locked) { mEditLock = locked; +} + +bool CSVWorld::CommandDelegate::isEditLocked() const +{ + return mEditLock; } \ No newline at end of file diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 79f30da2c..5334abf9c 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -85,13 +85,23 @@ namespace CSVWorld QUndoStack& mUndoStack; bool mEditLock; + protected: + + QUndoStack& getUndoStack() const; + + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; + public: CommandDelegate (QUndoStack& undoStack, QObject *parent); - void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + virtual void setModelData (QWidget *editor, QAbstractItemModel *model, + const QModelIndex& index) const; void setEditLock (bool locked); + + bool isEditLocked() const; }; } diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp new file mode 100644 index 000000000..3ee759ef2 --- /dev/null +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -0,0 +1,103 @@ + +#include "vartypedelegate.hpp" + +#include + +#include "../../model/world/commands.hpp" + +void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type) + const +{ + QModelIndex next = model->index (index.row(), index.column()+1); + + QVariant old = model->data (next); + + QVariant value; + + switch (type) + { + case ESM::VT_Short: + case ESM::VT_Int: + case ESM::VT_Long: + + value = old.toInt(); + break; + + case ESM::VT_Float: + + value = old.toFloat(); + break; + + case ESM::VT_String: + + value = old.toString(); + break; + + default: break; // ignore the rest + } + + getUndoStack().beginMacro ( + "Modify " + model->headerData (index.column(), Qt::Horizontal, Qt::DisplayRole).toString()); + + getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, type)); + getUndoStack().push (new CSMWorld::ModifyCommand (*model, next, value)); + + getUndoStack().endMacro(); +} + +CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent) +: EnumDelegate (values, undoStack, parent) +{} + + +CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0, + ESM::VarType type1, ESM::VarType type2, ESM::VarType type3) +{ + if (type0!=ESM::VT_Unknown) + add (type0); + + if (type1!=ESM::VT_Unknown) + add (type1); + + if (type2!=ESM::VT_Unknown) + add (type2); + + if (type3!=ESM::VT_Unknown) + add (type3); +} + +CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new VarTypeDelegate (mValues, undoStack, parent); +} + +void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) +{ + struct Name + { + ESM::VarType mType; + const char *mName; + }; + + static const Name sNames[] = + { + { ESM::VT_None, "empty" }, + { ESM::VT_Short, "short" }, + { ESM::VT_Int, "long" }, + { ESM::VT_Long, "long" }, + { ESM::VT_Float, "float" }, + { ESM::VT_String, "string" }, + { ESM::VT_Unknown, 0 } // end marker + }; + + for (int i=0; sNames[i].mName; ++i) + if (sNames[i].mType==type) + { + mValues.push_back (std::make_pair (type, sNames[i].mName)); + return; + } + + throw std::logic_error ("Unsupported variable type"); +} diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp new file mode 100644 index 000000000..621dd316b --- /dev/null +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -0,0 +1,38 @@ +#ifndef CSV_WORLD_VARTYPEDELEGATE_H +#define CSV_WORLD_VARTYPEDELEGATE_H + +#include "enumdelegate.hpp" + +namespace CSVWorld +{ + class VarTypeDelegate : public EnumDelegate + { + private: + + virtual void addCommands (QAbstractItemModel *model, + const QModelIndex& index, int type) const; + + public: + + VarTypeDelegate (const std::vector >& values, + QUndoStack& undoStack, QObject *parent); + }; + + class VarTypeDelegateFactory : public CommandDelegateFactory + { + std::vector > mValues; + + public: + + VarTypeDelegateFactory (ESM::VarType type0 = ESM::VT_Unknown, + ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown, + ESM::VarType type3 = ESM::VT_Unknown); + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + void add (ESM::VarType type); + }; +} + +#endif From 791d16bbdb6ff95c1b4be0adfe04ab945601e4b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 18:12:38 +0100 Subject: [PATCH 650/916] Use infinite AAB for sky meshes to fix them from disappearing from underwater refraction, while still taking advantage of CPU culling for other meshes --- apps/openmw/mwrender/refraction.cpp | 4 ++++ apps/openmw/mwrender/sky.cpp | 6 ++++++ apps/openmw/mwrender/water.cpp | 4 +++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index e6b6e3baa..a924be7d7 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -41,6 +41,7 @@ namespace MWRender mRenderTarget->removeListener(this); Ogre::TextureManager::getSingleton().remove("WaterRefraction"); mParentCamera->getSceneManager()->destroyCamera(mCamera); + mParentCamera->getSceneManager()->removeRenderQueueListener(this); } void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) @@ -53,6 +54,9 @@ namespace MWRender mCamera->setAspectRatio(mParentCamera->getAspectRatio()); mCamera->setFOVy(mParentCamera->getFOVy()); + // enable clip plane here to take advantage of CPU culling for overwater or underwater objects + mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); + mRenderActive = true; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index be989724a..3b02ca412 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -280,6 +280,9 @@ void SkyManager::create() mSunGlare->setRenderQueue(RQG_SkiesLate); mSunGlare->setVisibilityFlags(RV_NoReflection); + Ogre::AxisAlignedBox aabInf; + aabInf.setInfinite (); + // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif"); @@ -289,6 +292,7 @@ void SkyManager::create() night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); + night1_ent->getMesh()->_setBounds (aabInf); for (unsigned int j=0; jgetNumSubEntities(); ++j) { @@ -315,6 +319,7 @@ void SkyManager::create() atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); + atmosphere_ent->getMesh()->_setBounds (aabInf); } @@ -328,6 +333,7 @@ void SkyManager::create() clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); clouds_ent->setCastShadows(false); + clouds_ent->getMesh()->_setBounds (aabInf); } mCreated = true; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 33159024e..b006059a9 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -124,7 +124,6 @@ void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::St { if (queueGroupId < 20 && mRenderActive) { - // this trick does not seem to work well for extreme angles mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); } @@ -145,6 +144,9 @@ void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) pos.y = (mWaterPlane).d*2 - pos.y; mSky->setSkyPosition(pos); mCamera->enableReflection(mWaterPlane); + + // enable clip plane here to take advantage of CPU culling for overwater or underwater objects + mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); } void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) From 170a9762ac0127579c9df4cab14bc8d1732bb2f4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 18:30:21 +0100 Subject: [PATCH 651/916] Fix travel services not actually costing gold. --- apps/openmw/mwgui/travelwindow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 9615e95f7..465f588b8 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -132,6 +132,8 @@ namespace MWGui if (mWindowManager.getInventoryWindow()->getPlayerGold()addOrRemoveGold (-price); + MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); ESM::Position pos = *_sender->getUserData(); From e1ca0a15aec61c1bcc3eba325b12476e0600b41a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 18:58:54 +0100 Subject: [PATCH 652/916] Add message box when item is added to player's inventory --- apps/openmw/mwscript/containerextensions.cpp | 23 +++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 4cce19b86..68ae1b516 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -60,6 +60,27 @@ namespace MWScript } MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); + + // The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory + std::string msgBox; + std::string itemName = MWWorld::Class::get(ref.getPtr()).getName(ref.getPtr()); + if (count == 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); + std::stringstream temp; + temp << boost::format(msgBox) % itemName; + msgBox = temp.str(); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); + std::stringstream temp; + temp << boost::format(msgBox) % (count) % itemName; + msgBox = temp.str(); + } + + if(count > 0) + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); } }; @@ -130,7 +151,7 @@ namespace MWScript } } - /* The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory */ + // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory std::string msgBox; if(originalCount - count > 1) { From abd307d70e946b9efe259ce6c4ed54d8f2af6b53 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Feb 2013 19:26:01 +0100 Subject: [PATCH 653/916] Issue #567: workaround for crash with non-English ESX files --- apps/opencs/model/world/data.cpp | 6 +++++- apps/opencs/view/doc/opendialog.cpp | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f120c75f1..92bd2bdb0 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -72,7 +72,11 @@ void CSMWorld::Data::merge() void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) { ESM::ESMReader reader; - /// \todo set encoder + + /// \todo set encoding properly, once config implementation has been fixed. + ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252")); + reader.setEncoder (&encoder); + reader.open (path.string()); // Note: We do not need to send update signals here, because at this point the model is not connected diff --git a/apps/opencs/view/doc/opendialog.cpp b/apps/opencs/view/doc/opendialog.cpp index 9a5feb23a..7b62aafa3 100644 --- a/apps/opencs/view/doc/opendialog.cpp +++ b/apps/opencs/view/doc/opendialog.cpp @@ -10,48 +10,48 @@ OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent) QVBoxLayout *layout = new QVBoxLayout(this); mFileSelector = new DataFilesList(mCfgMgr, this); layout->addWidget(mFileSelector); - - //FIXME - same as DataFilesPage::setupDataFiles + + /// \todo move config to Editor class and add command line options. // We use the Configuration Manager to retrieve the configuration values boost::program_options::variables_map variables; boost::program_options::options_description desc; - + desc.add_options() ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) ("data-local", boost::program_options::value()->default_value("")) ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) ("encoding", boost::program_options::value()->default_value("win1252")); - + boost::program_options::notify(variables); - + mCfgMgr.readConfiguration(variables, desc); - + Files::PathContainer mDataDirs, mDataLocal; if (!variables["data"].empty()) { mDataDirs = Files::PathContainer(variables["data"].as()); } - + std::string local = variables["data-local"].as(); if (!local.empty()) { mDataLocal.push_back(Files::PathContainer::value_type(local)); } - + mCfgMgr.processPaths(mDataDirs); mCfgMgr.processPaths(mDataLocal); - + // Set the charset for reading the esm/esp files QString encoding = QString::fromStdString(variables["encoding"].as()); - + Files::PathContainer dataDirs; dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end()); dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end()); mFileSelector->setupDataFiles(dataDirs, encoding); - + buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); layout->addWidget(buttonBox); - + setLayout(layout); setWindowTitle(tr("Open")); } From 52d0f0b750ecca5b72892a6e815a1332299594fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 19:44:00 +0100 Subject: [PATCH 654/916] Fixed OpAddItem, OpRemoveItem --- apps/openmw/mwscript/containerextensions.cpp | 84 +++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 68ae1b516..81639b5be 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -21,6 +21,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwworld/player.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -47,6 +48,10 @@ namespace MWScript if (count<0) throw std::runtime_error ("second argument for AddItem must be non-negative"); + // no-op + if (count == 0) + return; + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item); ref.getPtr().getRefData().setCount (count); @@ -61,26 +66,25 @@ namespace MWScript MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr()); - // The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory - std::string msgBox; - std::string itemName = MWWorld::Class::get(ref.getPtr()).getName(ref.getPtr()); - if (count == 1) + // Spawn a messagebox (only for items added to player's inventory) + if (ptr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer()) { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); - std::stringstream temp; - temp << boost::format(msgBox) % itemName; - msgBox = temp.str(); - } - else - { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); - std::stringstream temp; - temp << boost::format(msgBox) % (count) % itemName; - msgBox = temp.str(); - } + // The two GMST entries below expand to strings informing the player of what, and how many of it has been added to their inventory + std::string msgBox; + std::string itemName = MWWorld::Class::get(ref.getPtr()).getName(ref.getPtr()); + if (count == 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage60}"); + msgBox = boost::str(boost::format(msgBox) % itemName); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage61}"); + msgBox = boost::str(boost::format(msgBox) % count % itemName); + } - if(count > 0) MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + } } }; @@ -122,13 +126,19 @@ namespace MWScript Interpreter::Type_Integer count = runtime[0].mInteger; runtime.pop(); - + if (count<0) throw std::runtime_error ("second argument for RemoveItem must be non-negative"); + // no-op + if (count == 0) + return; + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); std::string itemName = ""; + + // originalCount holds the total number of items to remove, count holds the remaining number of items to remove Interpreter::Type_Integer originalCount = count; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; @@ -151,28 +161,26 @@ namespace MWScript } } - // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory - std::string msgBox; - if(originalCount - count > 1) + // Spawn a messagebox (only for items added to player's inventory) + if (ptr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer()) { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); - std::stringstream temp; - temp << boost::format(msgBox) % (originalCount - count) % itemName; - msgBox = temp.str(); - } - else - { - msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); - std::stringstream temp; - temp << boost::format(msgBox) % itemName; - msgBox = temp.str(); - } - - if(originalCount - count > 0) - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory + std::string msgBox; + int numRemoved = (originalCount - count); + if(numRemoved > 1) + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); + msgBox = boost::str (boost::format(msgBox) % numRemoved % itemName); + } + else + { + msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}"); + msgBox = boost::str (boost::format(msgBox) % itemName); + } - // To be fully compatible with original Morrowind, we would need to check if - // count is >= 0 here and throw an exception. But let's be tollerant instead. + if (numRemoved > 0) + MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + } } }; From 475f4f9311d1d13348174130711dee02978c5f14 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Feb 2013 20:03:39 +0100 Subject: [PATCH 655/916] implicitly add Tribunal/Bloodmoon GMSTs to base, if present neither in base nor in modified --- apps/opencs/model/doc/document.cpp | 129 +++++++++++++++++++++++++++++ apps/opencs/model/doc/document.hpp | 9 ++ apps/opencs/model/world/data.cpp | 10 +++ apps/opencs/model/world/data.hpp | 4 + 4 files changed, 152 insertions(+) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 796135c3f..e8d3a4eef 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -18,6 +18,135 @@ void CSMDoc::Document::load (const std::vector::const_i if (lastAsModified) getData().loadFile (*end2, false); + + addOptionalGmsts(); +} + +void CSMDoc::Document::addOptionalGmsts() +{ + static const char *sFloats[] = + { + "fCombatDistanceWerewolfMod", + "fFleeDistance", + "fWereWolfAcrobatics", + "fWereWolfAgility", + "fWereWolfAlchemy", + "fWereWolfAlteration", + "fWereWolfArmorer", + "fWereWolfAthletics", + "fWereWolfAxe", + "fWereWolfBlock", + "fWereWolfBluntWeapon", + "fWereWolfConjuration", + "fWereWolfDestruction", + "fWereWolfEnchant", + "fWereWolfEndurance", + "fWereWolfFatigue", + "fWereWolfHandtoHand", + "fWereWolfHealth", + "fWereWolfHeavyArmor", + "fWereWolfIllusion", + "fWereWolfIntellegence", + "fWereWolfLightArmor", + "fWereWolfLongBlade", + "fWereWolfLuck", + "fWereWolfMagicka", + "fWereWolfMarksman", + "fWereWolfMediumArmor", + "fWereWolfMerchantile", + "fWereWolfMysticism", + "fWereWolfPersonality", + "fWereWolfRestoration", + "fWereWolfRunMult", + "fWereWolfSecurity", + "fWereWolfShortBlade", + "fWereWolfSilverWeaponDamageMult", + "fWereWolfSneak", + "fWereWolfSpear", + "fWereWolfSpeechcraft", + "fWereWolfSpeed", + "fWereWolfStrength", + "fWereWolfUnarmored", + "fWereWolfWillPower", + 0 + }; + + static const char *sIntegers[] = + { + "iWereWolfBounty", + "iWereWolfFightMod", + "iWereWolfFleeMod", + "iWereWolfLevelToAttack", + 0 + }; + + static const char *sStrings[] = + { + "sCompanionShare", + "sCompanionWarningButtonOne", + "sCompanionWarningButtonTwo", + "sCompanionWarningMessage", + "sDeleteNote", + "sEditNote", + "sEffectSummonCreature01", + "sEffectSummonCreature02", + "sEffectSummonCreature03", + "sEffectSummonCreature04", + "sEffectSummonCreature05", + "sEffectSummonFabricant", + "sLevitateDisabled", + "sMagicCreature01ID", + "sMagicCreature02ID", + "sMagicCreature03ID", + "sMagicCreature04ID", + "sMagicCreature05ID", + "sMagicFabricantID", + "sMaxSale", + "sProfitValue", + "sTeleportDisabled", + "sWerewolfAlarmMessage", + "sWerewolfPopup", + "sWerewolfRefusal", + "sWerewolfRestMessage", + 0 + }; + + for (int i=0; sFloats[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sFloats[i]; + gmst.mF = 0; + gmst.mType = ESM::VT_Float; + addOptionalGmst (gmst); + } + + for (int i=0; sIntegers[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sIntegers[i]; + gmst.mI = 0; + gmst.mType = ESM::VT_Long; + addOptionalGmst (gmst); + } + + for (int i=0; sStrings[i]; ++i) + { + ESM::GameSetting gmst; + gmst.mId = sStrings[i]; + gmst.mType = ESM::VT_String; + addOptionalGmst (gmst); + } +} + +void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) +{ + if (getData().getGmsts().searchId (gmst.mId)==-1) + { + CSMWorld::Record record; + record.mBase = gmst; + record.mState = CSMWorld::RecordBase::State_BaseOnly; + getData().getGmsts().appendRecord (record); + } } void CSMDoc::Document::createBase() diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 0162681bc..413e840d3 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -17,6 +17,11 @@ class QAbstractItemModel; +namespace ESM +{ + struct GameSetting; +} + namespace CSMDoc { class Document : public QObject @@ -46,6 +51,10 @@ namespace CSMDoc void createBase(); + void addOptionalGmsts(); + + void addOptionalGmst (const ESM::GameSetting& gmst); + public: Document (const std::vector& files, bool new_); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 92bd2bdb0..c59763f51 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -54,6 +54,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getGlobals() return mGlobals; } +const CSMWorld::IdCollection& CSMWorld::Data::getGmsts() const +{ + return mGmsts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getGmsts() +{ + return mGmsts; +} + QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 519817a3b..374534651 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -40,6 +40,10 @@ namespace CSMWorld IdCollection& getGlobals(); + const IdCollection& getGmsts() const; + + IdCollection& getGmsts(); + QAbstractTableModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// From b52df83d8461978478df3899fd537590e65baabd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Feb 2013 20:23:22 +0100 Subject: [PATCH 656/916] Pressing Enter should skip _one_ message box, not skip all message boxes until the key is released again --- apps/openmw/mwinput/inputmanagerimp.cpp | 17 +++++++---------- apps/openmw/mwinput/inputmanagerimp.hpp | 2 -- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index dc4c020d6..f1f88b9ae 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -51,7 +51,6 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) - , mEnterPressed(false) { Ogre::RenderWindow* window = ogre.getWindow (); size_t windowHnd; @@ -240,10 +239,6 @@ namespace MWInput void InputManager::update(float dt, bool loading) { - // Pressing enter when a messagebox is prompting for "ok" will activate the ok button - if(mEnterPressed && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox) - MWBase::Environment::get().getWindowManager()->enterPressed(); - // Tell OIS to handle all input events mKeyboard->capture(); mMouse->capture(); @@ -431,8 +426,13 @@ namespace MWInput bool InputManager::keyPressed( const OIS::KeyEvent &arg ) { - if(arg.key == OIS::KC_RETURN && MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console) - mEnterPressed = true; + if(arg.key == OIS::KC_RETURN + && MWBase::Environment::get().getWindowManager()->isGuiMode() + && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) + { + // Pressing enter when a messagebox is prompting for "ok" will activate the ok button + MWBase::Environment::get().getWindowManager()->enterPressed(); + } mInputCtrl->keyPressed (arg); unsigned int text = arg.text; @@ -450,9 +450,6 @@ namespace MWInput bool InputManager::keyReleased( const OIS::KeyEvent &arg ) { - if(arg.key == OIS::KC_RETURN) - mEnterPressed = false; - mInputCtrl->keyReleased (arg); MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key)); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index c7ba7b756..9deed1f28 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -151,8 +151,6 @@ namespace MWInput std::map mControlSwitch; - bool mEnterPressed; - private: void adjustMouseRegion(int width, int height); From 42883ec64bdfbabb32735757230ad79790bc4ed7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 Feb 2013 02:33:53 +0100 Subject: [PATCH 657/916] cleanup --- apps/openmw/engine.cpp | 1 - apps/openmw/mwrender/localmap.cpp | 2 - apps/openmw/mwrender/renderingmanager.cpp | 21 ------ apps/openmw/mwrender/renderingmanager.hpp | 2 - apps/openmw/mwrender/water.cpp | 20 ----- apps/openmw/mwrender/water.hpp | 2 - files/CMakeLists.txt | 7 -- files/gbuffer/gbuffer.compositor | 91 ----------------------- files/materials/atmosphere.shader | 9 --- files/materials/clouds.shader | 9 --- files/materials/moon.shader | 10 --- files/materials/objects.shader | 20 +---- files/materials/openmw.configuration | 2 - files/materials/quad.mat | 13 ---- files/materials/quad.shaderset | 16 ---- files/materials/quad2.shader | 23 ------ files/materials/stars.shader | 10 --- files/materials/sun.shader | 10 --- files/materials/terrain.shader | 12 +-- files/materials/water.shader | 13 +--- 20 files changed, 6 insertions(+), 287 deletions(-) delete mode 100644 files/gbuffer/gbuffer.compositor delete mode 100644 files/materials/quad2.shader diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 340e1d381..d65a5a78c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -319,7 +319,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); - addResourcesDirectory(mResDir / "gbuffer"); addResourcesDirectory(mResDir / "shadows"); addZipResource(mResDir / "mygui" / "Obliviontt.zip"); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index e0b7d9a11..de36dcbbf 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -236,8 +236,6 @@ void LocalMap::render(const float x, const float y, vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0, 0, 0)); vp->setVisibilityMask(RV_Map); - - // use fallback techniques without shadows and without mrt vp->setMaterialScheme("local_map"); rtt->update(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fe8f3e99b..6c6c47417 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -126,7 +126,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); - sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("fog", "true"); sh::Factory::getInstance ().setGlobalSetting ("lighting", "true"); sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); @@ -690,11 +689,6 @@ void RenderingManager::enableLights(bool sun) sunEnable(sun); } -const bool RenderingManager::useMRT() -{ - return Settings::Manager::getBool("shader", "Water"); -} - Shadows* RenderingManager::getShadows() { return mShadows; @@ -795,7 +789,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec else if (it->second == "shader" && it->first == "Water") { applyCompositors(); - sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); rebuild = true; mRendering.getViewport ()->setClearEveryFrame (true); @@ -873,7 +866,6 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw) mRendering.adjustViewport(); mCompositors->recreate(); - mWater->assignTextures(); mVideoPlayer->setResolution (rw->getWidth(), rw->getHeight()); @@ -897,19 +889,6 @@ bool RenderingManager::waterShaderSupported() void RenderingManager::applyCompositors() { - mCompositors->removeAll(); - if (useMRT()) - { - /* - mCompositors->addCompositor("gbuffer", 0); - mCompositors->setCompositorEnabled("gbuffer", true); - mCompositors->addCompositor("gbufferFinalizer", 2); - mCompositors->setCompositorEnabled("gbufferFinalizer", true); - */ - } - - //if (mWater) - //mWater->assignTextures(); } void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 71ac742c2..e42c6e06f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -104,8 +104,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void removeWater(); - static const bool useMRT(); - void preCellChange (MWWorld::CellStore* store); ///< this event is fired immediately before changing cell diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index b006059a9..f71431a27 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -93,7 +93,6 @@ PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* s vp->setOverlaysEnabled(false); vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setShadowsEnabled(false); - // use fallback techniques without shadows and without mrt vp->setMaterialScheme("water_reflection"); mRenderTarget->addListener(this); mRenderTarget->setActive(true); @@ -232,8 +231,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel underwaterDome->setMaterialName("Underwater_Dome"); */ - assignTextures(); - setHeight(mTop); sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); @@ -362,22 +359,6 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); } -void Water::assignTextures() -{ - if (Settings::Manager::getBool("shader", "Water")) - { -/* - CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mRendering->getViewport())->getCompositor("gbuffer"); - - TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); - sh::Factory::getInstance ().setTextureAlias ("WaterRefraction", colorTexture->getName()); - - TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1); - sh::Factory::getInstance ().setTextureAlias ("SceneDepth", depthTexture->getName()); - */ - } -} - void Water::setViewportBackground(const ColourValue& bg) { if (mReflection) @@ -483,7 +464,6 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin applyRTT(); applyVisibilityMask(); mWater->setMaterial(mMaterial); - assignTextures(); } if (applyVisMask) applyVisibilityMask(); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 9aa18f008..6100b7cfd 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -146,8 +146,6 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); - void assignTextures(); - void setViewportBackground(const Ogre::ColourValue& bg); void processChangedSettings(const Settings::CategorySettingVector& settings); diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 65ebc31a2..c29d917b8 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -6,10 +6,6 @@ set(WATER_FILES circle.png ) -set(GBUFFER_FILES - gbuffer.compositor -) - set(MATERIAL_FILES atmosphere.shader atmosphere.shaderset @@ -22,7 +18,6 @@ set(MATERIAL_FILES objects.shader objects.shaderset openmw.configuration - quad2.shader quad.mat quad.shader quad.shaderset @@ -54,6 +49,4 @@ set(MATERIAL_FILES copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") -copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer "${OpenMW_BINARY_DIR}/resources/gbuffer/" "${GBUFFER_FILES}") - copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor deleted file mode 100644 index 0a0675fa0..000000000 --- a/files/gbuffer/gbuffer.compositor +++ /dev/null @@ -1,91 +0,0 @@ -// Compositor that just controls output to the MRT textures -compositor gbuffer -{ - technique - { - // MRT output. Currently this is a color texture plus a depth texture - texture mrt_output target_width target_height PF_FLOAT16_RGBA PF_FLOAT16_RGBA chain_scope depth_pool 2 - - target mrt_output - { - input none - - pass clear - { - colour_value 0 0 0 1 - } - pass render_quad - { - // this makes sure the depth for background is set to 1 - material openmw_viewport_init - } - pass render_scene - { - // Renders everything except water - first_render_queue 0 - last_render_queue 50 - } - - } - - target_output - { - input none - - pass render_quad - { - material quad - input 0 mrt_output 0 - } - } - } -} - -// Finalizer compositor to render objects that we don't want in the MRT textures (ex. water) -// NB the water has to be rendered in a seperate compositor anyway, because it -// accesses the MRT textures which can't be done while they are still being rendered to. -compositor gbufferFinalizer -{ - technique - { - texture no_mrt_output target_width target_height PF_R8G8B8A8 depth_pool 2 no_fsaa - texture previousscene target_width target_height PF_R8G8B8A8 - - target previousscene - { - input previous - } - target no_mrt_output - { - input none - shadows off - pass clear - { - buffers colour - colour_value 0 0 0 0 - } - pass render_quad - { - material quad_noDepthWrite - input 0 previousscene - } - pass render_scene - { - first_render_queue 51 - last_render_queue 105 - } - } - target_output - { - input none - pass clear - { - } - pass render_quad - { - material quad_noDepthWrite - input 0 no_mrt_output - } - } - } -} diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 16edc78c5..5d71d7c32 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -1,7 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -19,18 +17,11 @@ SH_BEGIN_PROGRAM shInput(float, alphaFade) -#if MRT - shDeclareMrtOutput(1) -#endif shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) SH_START_PROGRAM { shOutputColour(0) = atmosphereColour * float4(1,1,1,alphaFade); - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index 4b1868fb4..e60026d3b 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -1,7 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -22,9 +20,6 @@ SH_BEGIN_PROGRAM shInput(float2, UV) shInput(float, alphaFade) -#if MRT - shDeclareMrtOutput(1) -#endif shSampler2D(diffuseMap1) shSampler2D(diffuseMap2) @@ -42,10 +37,6 @@ float4 albedo = shSample(diffuseMap1, scrolledUV) * (1-cloudBlendFactor) + shSample(diffuseMap2, scrolledUV) * cloudBlendFactor; shOutputColour(0) = float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity * alphaFade); - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif diff --git a/files/materials/moon.shader b/files/materials/moon.shader index 02f3d8001..231f60ba0 100644 --- a/files/materials/moon.shader +++ b/files/materials/moon.shader @@ -1,8 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -22,9 +19,6 @@ shSampler2D(diffuseMap) shSampler2D(alphaMap) shInput(float2, UV) -#if MRT - shDeclareMrtOutput(1) -#endif shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) @@ -42,10 +36,6 @@ shOutputColour(0).rgb += (1-tex.a) * shOutputColour(0).a * atmosphereColour.rgb; //fill dark side of moon with atmosphereColour shOutputColour(0).rgb += (1-materialDiffuse.a) * atmosphereColour.rgb; //fade bump -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif - } #endif diff --git a/files/materials/objects.shader b/files/materials/objects.shader index af596b779..3f5aa418f 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -2,7 +2,6 @@ #define FOG @shGlobalSettingBool(fog) -#define MRT @shPropertyNotBool(is_transparent) && @shGlobalSettingBool(mrt_output) #define LIGHTING @shGlobalSettingBool(lighting) #define SHADOWS_PSSM LIGHTING && @shGlobalSettingBool(shadows_pssm) @@ -12,7 +11,7 @@ #include "shadows.h" #endif -#if FOG || MRT || SHADOWS_PSSM +#if FOG || SHADOWS_PSSM #define NEED_DEPTH #endif @@ -51,9 +50,9 @@ #if VERTEX_LIGHTING shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) - shUniform(float4, lightPosition[8]) @shAutoConstant(lightPosition, light_position_object_space_array, 8) - shUniform(float4, lightDiffuse[8]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, 8) - shUniform(float4, lightAttenuation[8]) @shAutoConstant(lightAttenuation, light_attenuation_array, 8) + shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_object_space_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) #if !HAS_VERTEXCOLOUR shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) @@ -153,18 +152,11 @@ SH_BEGIN_PROGRAM shSampler2D(diffuseMap) shInput(float2, UV) -#if MRT - shDeclareMrtOutput(1) -#endif #ifdef NEED_DEPTH shInput(float, depthPassthrough) #endif -#if MRT - shUniform(float, far) @shAutoConstant(far, far_clip_distance) -#endif - #if LIGHTING shInput(float3, normalPassthrough) shInput(float3, objSpacePositionPassthrough) @@ -369,10 +361,6 @@ float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); #endif - -#if MRT - shOutputColour(1) = float4(depthPassthrough / far,1,1,1); -#endif } #endif diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index db3693dd6..870c96728 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -3,13 +3,11 @@ configuration water_reflection fog false shadows false shadows_pssm false - mrt_output false } configuration local_map { fog false - mrt_output false shadows false shadows_pssm false simple_water true diff --git a/files/materials/quad.mat b/files/materials/quad.mat index a484d7f28..77a2c0c34 100644 --- a/files/materials/quad.mat +++ b/files/materials/quad.mat @@ -20,16 +20,3 @@ material quad_noDepthWrite parent quad depth_write off } - -material openmw_viewport_init -{ - pass - { - vertex_program viewport_init_vertex - fragment_program viewport_init_fragment - - depth_write off - depth_check off - scene_blend add - } -} diff --git a/files/materials/quad.shaderset b/files/materials/quad.shaderset index ee230a303..71fd82da4 100644 --- a/files/materials/quad.shaderset +++ b/files/materials/quad.shaderset @@ -13,19 +13,3 @@ shader_set quad_fragment profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 profiles_hlsl ps_2_0 } - -shader_set viewport_init_vertex -{ - source quad2.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set viewport_init_fragment -{ - source quad2.shader - type fragment - profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 - profiles_hlsl ps_2_0 -} diff --git a/files/materials/quad2.shader b/files/materials/quad2.shader deleted file mode 100644 index e54d83ef4..000000000 --- a/files/materials/quad2.shader +++ /dev/null @@ -1,23 +0,0 @@ -#include "core.h" - -#ifdef SH_VERTEX_SHADER - - SH_BEGIN_PROGRAM - shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) - SH_START_PROGRAM - { - shOutputPosition = shMatrixMult(wvp, shInputPosition); - } - -#else - - SH_BEGIN_PROGRAM - shUniform(float3, viewportBackground) @shSharedParameter(viewportBackground) - shDeclareMrtOutput(1) - SH_START_PROGRAM - { - shOutputColour(0) = float4(viewportBackground, 1); - shOutputColour(1) = float4(1,1,1,1); - } - -#endif diff --git a/files/materials/stars.shader b/files/materials/stars.shader index 5a55d171e..fea007424 100644 --- a/files/materials/stars.shader +++ b/files/materials/stars.shader @@ -1,7 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -22,9 +20,6 @@ #else SH_BEGIN_PROGRAM -#if MRT - shDeclareMrtOutput(1) -#endif shInput(float2, UV) shInput(float, fade) @@ -36,11 +31,6 @@ SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV) * float4(1,1,1, nightFade * fade); - - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif diff --git a/files/materials/sun.shader b/files/materials/sun.shader index 45cd2f24b..7954f417c 100644 --- a/files/materials/sun.shader +++ b/files/materials/sun.shader @@ -1,8 +1,5 @@ #include "core.h" -#define MRT @shGlobalSettingBool(mrt_output) - - #ifdef SH_VERTEX_SHADER SH_BEGIN_PROGRAM @@ -21,19 +18,12 @@ SH_BEGIN_PROGRAM shSampler2D(diffuseMap) shInput(float2, UV) -#if MRT - shDeclareMrtOutput(1) -#endif shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) //shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) SH_START_PROGRAM { shOutputColour(0) = float4(1,1,1,materialDiffuse.a) * shSample(diffuseMap, UV); - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index d62bb4035..497463f8e 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -3,7 +3,6 @@ #define IS_FIRST_PASS 1 #define FOG @shGlobalSettingBool(fog) -#define MRT @shGlobalSettingBool(mrt_output) #define LIGHTING @shGlobalSettingBool(lighting) @@ -18,7 +17,7 @@ #define NUM_LAYERS @shPropertyString(num_layers) -#if MRT || FOG || SHADOWS_PSSM +#if FOG || SHADOWS_PSSM #define NEED_DEPTH 1 #endif @@ -152,11 +151,6 @@ #endif @shPassthroughFragmentInputs - -#if MRT - shDeclareMrtOutput(1) - shUniform(float, far) @shAutoConstant(far, far_clip_distance) -#endif #if LIGHTING @@ -370,10 +364,6 @@ float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); #endif - -#if MRT - shOutputColour(1) = float4(depth / far,1,1,1); -#endif } #endif diff --git a/files/materials/water.shader b/files/materials/water.shader index 400fbefb2..ac6b81240 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -5,11 +5,7 @@ #if SIMPLE_WATER - // --------------------------------------- SIMPLE WATER --------------------------------------------------- - - - #define MRT @shGlobalSettingBool(mrt_output) - + // --------------------------------------- SIMPLE WATER --------------------------------------------------- #ifdef SH_VERTEX_SHADER @@ -32,9 +28,6 @@ shSampler2D(animatedTexture) shInput(float2, UV) shInput(float, depth) -#if MRT - shDeclareMrtOutput(1) -#endif shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) @@ -47,10 +40,6 @@ float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); - -#if MRT - shOutputColour(1) = float4(1,1,1,1); -#endif } #endif From a50ff34774225cd12905a8c7e05740d07b2b5e16 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Feb 2013 09:23:14 +0100 Subject: [PATCH 658/916] better default value for string GMSTs --- apps/opencs/model/doc/document.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e8d3a4eef..da29f6c68 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -133,6 +133,7 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sStrings[i]; + gmst.mStr = ""; gmst.mType = ESM::VT_String; addOptionalGmst (gmst); } From f2948ced2366d126cd8a9870e26a08f9268f974c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 03:07:31 -0800 Subject: [PATCH 659/916] Allow diagonal movement --- apps/openmw/mwmechanics/character.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 376092256..672ab2e9a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,6 +172,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) Ogre::Vector3 CharacterController::update(float duration) { + Ogre::Vector3 movement(0.0f); + const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); @@ -190,22 +192,28 @@ Ogre::Vector3 CharacterController::update(float duration) setState(isrunning ? (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + // Apply any forward/backward movement manually + movement.y += vec.y * (speed*duration); + } + else if(vec.y != 0.0f) + { + if(vec.y > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + else if(vec.y < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + // Apply any sideways movement manually + movement.x += vec.x * (speed*duration); } - else if(vec.y > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunForward : CharState_RunForward) : - (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); - else if(vec.y < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunBack : CharState_RunBack) : - (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); else { if(!(getState() >= CharState_Death1)) setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } - Ogre::Vector3 movement = Ogre::Vector3::ZERO; if(mAnimation && !mSkipAnim) { mAnimation->setSpeed(speed); From 627b866744b20524027eca4911e43b9c48e2df25 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 06:29:16 -0800 Subject: [PATCH 660/916] Don't try to set a new state when dead --- apps/openmw/mwmechanics/character.cpp | 71 ++++++++++++++------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 672ab2e9a..27bc62d07 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -174,43 +174,44 @@ Ogre::Vector3 CharacterController::update(float duration) { Ogre::Vector3 movement(0.0f); - const MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::Class &cls = MWWorld::Class::get(mPtr); - const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - const float speed = cls.getSpeed(mPtr); + float speed = 0.0f; + if(!(getState() >= CharState_Death1)) + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Class &cls = MWWorld::Class::get(mPtr); + const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); - bool inwater = world->isSwimming(mPtr); - bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); + bool inwater = world->isSwimming(mPtr); + bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); + speed = cls.getSpeed(mPtr); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) - { - if(vec.x > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunRight : CharState_RunRight) : - (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); - else if(vec.x < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : - (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); - // Apply any forward/backward movement manually - movement.y += vec.y * (speed*duration); - } - else if(vec.y != 0.0f) - { - if(vec.y > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunForward : CharState_RunForward) : - (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); - else if(vec.y < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunBack : CharState_RunBack) : - (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); - // Apply any sideways movement manually - movement.x += vec.x * (speed*duration); - } - else - { - if(!(getState() >= CharState_Death1)) + if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + { + if(vec.x > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunRight : CharState_RunRight) : + (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); + else if(vec.x < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : + (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + // Apply any forward/backward movement manually + movement.y += vec.y * (speed*duration); + } + else if(vec.y != 0.0f) + { + if(vec.y > 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunForward : CharState_RunForward) : + (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + else if(vec.y < 0.0f) + setState(isrunning ? + (inwater ? CharState_SwimRunBack : CharState_RunBack) : + (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + // Apply any sideways movement manually + movement.x += vec.x * (speed*duration); + } + else setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } From 178cf2154e1d33d24ddd649387beab13c0696a0d Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 18 Feb 2013 17:59:08 +0100 Subject: [PATCH 661/916] Made checking/unchecking work with the new datafiles model --- apps/launcher/datafilespage.cpp | 333 +++++------------- apps/launcher/datafilespage.hpp | 6 +- apps/launcher/settings/gamesettings.cpp | 2 + .../fileorderlist/model/datafilesmodel.cpp | 9 +- 4 files changed, 95 insertions(+), 255 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index fe6c6f424..ed24f881b 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -56,12 +56,25 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam , QWidget(parent) { // Models - mMastersModel = new DataFilesModel(this); - mPluginsModel = new DataFilesModel(this); + mDataFilesModel = new DataFilesModel(this); + mDataFilesModel->setObjectName(QString("mDataFilesModel")); + + mMastersProxyModel = new QSortFilterProxyModel(); + mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm")); + mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mMastersProxyModel->setSourceModel(mDataFilesModel); mPluginsProxyModel = new QSortFilterProxyModel(); - mPluginsProxyModel->setDynamicSortFilter(true); - mPluginsProxyModel->setSourceModel(mPluginsModel); + mPluginsProxyModel->setObjectName(QString("mPluginsProxyModel")); + mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); + mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mPluginsProxyModel->setSourceModel(mDataFilesModel); + + mFilterProxyModel = new QSortFilterProxyModel(); + mFilterProxyModel->setObjectName(QString("mFilterProxyModel")); + + mFilterProxyModel->setDynamicSortFilter(true); + mFilterProxyModel->setSourceModel(mPluginsProxyModel); // Filter toolbar QLabel *filterLabel = new QLabel(tr("&Filter:"), this); @@ -86,7 +99,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam unsigned int height = checkBox.sizeHint().height() + 4; mMastersTable = new QTableView(this); - mMastersTable->setModel(mMastersModel); + mMastersTable->setModel(mMastersProxyModel); mMastersTable->setObjectName("MastersTable"); mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection); @@ -109,7 +122,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersTable->setColumnHidden(8, true); mPluginsTable = new QTableView(this); - mPluginsTable->setModel(mPluginsProxyModel); + mPluginsTable->setModel(mFilterProxyModel); mPluginsTable->setObjectName("PluginsTable"); mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -172,7 +185,14 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); + + connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + + connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); + connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); @@ -219,69 +239,20 @@ void DataFilesPage::createActions() mContextMenu->addAction(mUncheckAction); } -void DataFilesPage::readConfig() -{ -// // Don't read the config if no masters are found -// if (mMastersModel->rowCount() < 1) -// return; - -// QString profile = mProfilesComboBox->currentText(); - -// // Make sure we have no groups open -// while (!mLauncherConfig->group().isEmpty()) { -// mLauncherConfig->endGroup(); -// } - -// mLauncherConfig->beginGroup("Profiles"); -// mLauncherConfig->beginGroup(profile); - -// QStringList childKeys = mLauncherConfig->childKeys(); -// QStringList plugins; - -// // Sort the child keys numerical instead of alphabetically -// // i.e. Plugin1, Plugin2 instead of Plugin1, Plugin10 -// qSort(childKeys.begin(), childKeys.end(), naturalSortLessThanCI); - -// foreach (const QString &key, childKeys) { -// const QString keyValue = mLauncherConfig->value(key).toString(); - -// if (key.startsWith("Plugin")) { -// //QStringList checked = mPluginsModel->checkedItems(); -// EsmFile *file = mPluginsModel->findItem(keyValue); -// QModelIndex index = mPluginsModel->indexFromItem(file); - -// mPluginsModel->setCheckState(index, Qt::Checked); -// // Move the row to the top of te view -// //mPluginsModel->moveRow(index.row(), checked.count()); -// plugins << keyValue; -// } - -// if (key.startsWith("Master")) { -// EsmFile *file = mMastersModel->findItem(keyValue); -// mMastersModel->setCheckState(mMastersModel->indexFromItem(file), Qt::Checked); -// } -// } - -// qDebug() << plugins; -} - void DataFilesPage::setupDataFiles() { // Set the encoding to the one found in openmw.cfg or the default - mMastersModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); - mPluginsModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); + mDataFilesModel->setEncoding(mGameSettings.value(QString("encoding"), QString("win1252"))); QStringList paths = mGameSettings.getDataDirs(); foreach (const QString &path, paths) { - mMastersModel->addMasters(path); - mPluginsModel->addPlugins(path); + mDataFilesModel->addFiles(path); } QString dataLocal = mGameSettings.getDataLocal(); if (!dataLocal.isEmpty()) { - mMastersModel->addMasters(dataLocal); - mPluginsModel->addPlugins(dataLocal); + mDataFilesModel->addFiles(dataLocal); } QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); @@ -313,29 +284,26 @@ void DataFilesPage::loadSettings() qDebug() << mLauncherSettings.values(QString("Profiles/Default"), Qt::MatchStartsWith); - - if (profile.isEmpty()) return; - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); + mDataFilesModel->uncheckAll(); QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly); QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly); qDebug() << "masters to check " << plugins; foreach (const QString &master, masters) { - QModelIndex index = mMastersModel->indexFromItem(mMastersModel->findItem(master)); + QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(master)); if (index.isValid()) - mMastersModel->setCheckState(index, Qt::Checked); + mDataFilesModel->setCheckState(index, Qt::Checked); } foreach (const QString &plugin, plugins) { - QModelIndex index = mPluginsModel->indexFromItem(mPluginsModel->findItem(plugin)); + QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(plugin)); if (index.isValid()) - mPluginsModel->setCheckState(index, Qt::Checked); + mDataFilesModel->setCheckState(index, Qt::Checked); } } @@ -352,178 +320,22 @@ void DataFilesPage::saveSettings() mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); - QStringList items = mMastersModel->checkedItems(); + QStringList items = mDataFilesModel->checkedItems(); - foreach(const QString &master, items) { - qDebug() << "setting " << master; - mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), master); - } + foreach(const QString &item, items) { - items.clear(); - items = mPluginsModel->checkedItems(); + if (item.endsWith(QString(".esm"), Qt::CaseInsensitive)) { + qDebug() << "setting " << item; + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), item); - qDebug() << items.size(); - - foreach(const QString &plugin, items) { - qDebug() << "setting " << plugin; - mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), plugin); + } else if (item.endsWith(QString(".esp"), Qt::CaseInsensitive)) { + qDebug() << "setting " << item; + mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), item); + } } } -void DataFilesPage::writeConfig(QString profile) -{ - -// // Don't overwrite the config if no masters are found -// if (mMastersModel->rowCount() < 1) -// return; - -// QString pathStr = QString::fromStdString(mCfgMgr.getUserPath().string()); -// QDir userPath(pathStr); - -// if (!userPath.exists()) { -// if (!userPath.mkpath(pathStr)) { -// QMessageBox msgBox; -// msgBox.setWindowTitle("Error creating OpenMW configuration directory"); -// msgBox.setIcon(QMessageBox::Critical); -// msgBox.setStandardButtons(QMessageBox::Ok); -// msgBox.setText(tr("
Could not create %0

\ -// Please make sure you have the right permissions and try again.
").arg(pathStr)); -// msgBox.exec(); - -// qApp->quit(); -// return; -// } -// } -// // Open the OpenMW config as a QFile -// QFile file(pathStr.append("openmw.cfg")); - -// if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { -// // File cannot be opened or created -// QMessageBox msgBox; -// msgBox.setWindowTitle("Error writing OpenMW configuration file"); -// msgBox.setIcon(QMessageBox::Critical); -// msgBox.setStandardButtons(QMessageBox::Ok); -// msgBox.setText(tr("
Could not open or create %0

\ -// Please make sure you have the right permissions and try again.
").arg(file.fileName())); -// msgBox.exec(); - -// qApp->quit(); -// return; -// } - -// QTextStream in(&file); -// QByteArray buffer; - -// // Remove all previous entries from config -// while (!in.atEnd()) { -// QString line = in.readLine(); -// if (!line.startsWith("master") && -// !line.startsWith("plugin") && -// !line.startsWith("data") && -// !line.startsWith("data-local")) -// { -// buffer += line += "\n"; -// } -// } - -// file.close(); - -// // Now we write back the other config entries -// if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { -// QMessageBox msgBox; -// msgBox.setWindowTitle("Error writing OpenMW configuration file"); -// msgBox.setIcon(QMessageBox::Critical); -// msgBox.setStandardButtons(QMessageBox::Ok); -// msgBox.setText(tr("
Could not write to %0

\ -// Please make sure you have the right permissions and try again.
").arg(file.fileName())); -// msgBox.exec(); - -// qApp->quit(); -// return; -// } - -// if (!buffer.isEmpty()) { -// file.write(buffer); -// } - -// QTextStream gameConfig(&file); - - -// QString path; - -// // data= directories -// for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) { -// path = QString::fromStdString(it->string()); -// path.remove(QChar('\"')); - -// // Make sure the string is quoted when it contains spaces -// if (path.contains(" ")) { -// gameConfig << "data=\"" << path << "\"" << endl; -// } else { -// gameConfig << "data=" << path << endl; -// } -// } - -// // data-local directory -// if (!mDataLocal.empty()) { -// path = QString::fromStdString(mDataLocal.front().string()); -// path.remove(QChar('\"')); - -// if (path.contains(" ")) { -// gameConfig << "data-local=\"" << path << "\"" << endl; -// } else { -// gameConfig << "data-local=" << path << endl; -// } -// } - - -// if (profile.isEmpty()) -// profile = mProfilesComboBox->currentText(); - -// if (profile.isEmpty()) -// return; - -// // Make sure we have no groups open -// while (!mLauncherConfig->group().isEmpty()) { -// mLauncherConfig->endGroup(); -// } - -// mLauncherConfig->beginGroup("Profiles"); -// mLauncherConfig->setValue("CurrentProfile", profile); - -// // Open the profile-name subgroup -// mLauncherConfig->beginGroup(profile); -// mLauncherConfig->remove(""); // Clear the subgroup - -// // Now write the masters to the configs -// const QStringList masters = mMastersModel->checkedItems(); - -// // We don't use foreach because we need i -// for (int i = 0; i < masters.size(); ++i) { -// const QString currentMaster = masters.at(i); - -// mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster); -// gameConfig << "master=" << currentMaster << endl; - -// } - -// // And finally write all checked plugins -// const QStringList plugins = mPluginsModel->checkedItems(); - -// for (int i = 0; i < plugins.size(); ++i) { -// const QString currentPlugin = plugins.at(i); -// mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin); -// gameConfig << "plugin=" << currentPlugin << endl; -// } - -// file.close(); -// mLauncherConfig->endGroup(); -// mLauncherConfig->endGroup(); -// mLauncherConfig->sync(); -} - - void DataFilesPage::newProfile() { if (mNewProfileDialog->exec() == QDialog::Accepted) { @@ -599,7 +411,13 @@ void DataFilesPage::check() if (!index.isValid()) return; - mPluginsModel->setCheckState(index, Qt::Checked); + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); } } @@ -619,13 +437,19 @@ void DataFilesPage::uncheck() if (!index.isValid()) return; - mPluginsModel->setCheckState(index, Qt::Unchecked); + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked); } } void DataFilesPage::refresh() { - mPluginsModel->sort(0); + mDataFilesModel->sort(0); // Refresh the plugins table mPluginsTable->scrollToTop(); @@ -643,28 +467,35 @@ void DataFilesPage::setCheckState(QModelIndex index) if (!object) return; - if (object->objectName() == QLatin1String("PluginsTable")) { - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource(index); - (mPluginsModel->checkState(sourceIndex) == Qt::Checked) - ? mPluginsModel->setCheckState(sourceIndex, Qt::Unchecked) - : mPluginsModel->setCheckState(sourceIndex, Qt::Checked); + if (object->objectName() == QLatin1String("PluginsTable")) { + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (sourceIndex.isValid()) { + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); + } } if (object->objectName() == QLatin1String("MastersTable")) { - (mMastersModel->checkState(index) == Qt::Checked) - ? mMastersModel->setCheckState(index, Qt::Unchecked) - : mMastersModel->setCheckState(index, Qt::Checked); + QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); + + if (sourceIndex.isValid()) { + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); + } } return; - } void DataFilesPage::filterChanged(const QString filter) { QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); - mPluginsProxyModel->setFilterRegExp(regExp); + mFilterProxyModel->setFilterRegExp(regExp); } void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) @@ -690,8 +521,7 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre saveSettings(); mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); + mDataFilesModel->uncheckAll(); loadSettings(); } @@ -712,8 +542,7 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre // Remove the profile from the combobox mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - mMastersModel->uncheckAll(); - mPluginsModel->uncheckAll(); + mDataFilesModel->uncheckAll(); loadSettings(); } @@ -737,7 +566,13 @@ void DataFilesPage::showContextMenu(const QPoint &point) if (!index.isValid()) return; - (mPluginsModel->checkState(index) == Qt::Checked) + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) ? mUncheckAction->setEnabled(true) : mCheckAction->setEnabled(true); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index ef03e4ad4..e6b4194bd 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -56,10 +56,12 @@ public slots: void refresh(); private: - DataFilesModel *mMastersModel; - DataFilesModel *mPluginsModel; + DataFilesModel *mDataFilesModel; QSortFilterProxyModel *mPluginsProxyModel; + QSortFilterProxyModel *mMastersProxyModel; + + QSortFilterProxyModel *mFilterProxyModel; QTableView *mMastersTable; QTableView *mPluginsTable; diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 5f0fb77bc..f87937228 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -155,4 +155,6 @@ bool GameSettings::writeFile(QTextStream &stream) } } + + return true; } diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 09cffad7a..036394800 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -204,13 +204,14 @@ bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, in return false; if (role == Qt::CheckStateRole) { - - emit layoutAboutToBeChanged(); - QString name = item(index.row())->fileName(); mCheckStates[name] = static_cast(value.toInt()); - emit layoutChanged(); + // Force a redraw of the view since unchecking one item can affect another + QModelIndex firstIndex = indexFromItem(mFiles.first()); + QModelIndex lastIndex = indexFromItem(mFiles.last()); + + emit dataChanged(firstIndex, lastIndex); return true; } From bcf4f962098a5e48eb3662b045d8692b50cf0eda Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 18 Feb 2013 23:10:50 +0100 Subject: [PATCH 662/916] Added writing masters/plugins to openmw.cfg --- apps/launcher/datafilespage.cpp | 21 +++++---------------- apps/launcher/settings/gamesettings.hpp | 12 ++++++++++++ apps/launcher/settings/settingsbase.hpp | 7 +------ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index ed24f881b..e0ebefa58 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -57,7 +57,6 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam { // Models mDataFilesModel = new DataFilesModel(this); - mDataFilesModel->setObjectName(QString("mDataFilesModel")); mMastersProxyModel = new QSortFilterProxyModel(); mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm")); @@ -65,14 +64,11 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersProxyModel->setSourceModel(mDataFilesModel); mPluginsProxyModel = new QSortFilterProxyModel(); - mPluginsProxyModel->setObjectName(QString("mPluginsProxyModel")); mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); mPluginsProxyModel->setSourceModel(mDataFilesModel); mFilterProxyModel = new QSortFilterProxyModel(); - mFilterProxyModel->setObjectName(QString("mFilterProxyModel")); - mFilterProxyModel->setDynamicSortFilter(true); mFilterProxyModel->setSourceModel(mPluginsProxyModel); @@ -155,7 +151,6 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam QList sizeList; sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt(); sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt(); - qDebug() << sizeList; mSplitter->setSizes(sizeList); @@ -279,20 +274,15 @@ void DataFilesPage::setupDataFiles() void DataFilesPage::loadSettings() { - qDebug() << "load settings"; QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); - qDebug() << mLauncherSettings.values(QString("Profiles/Default"), Qt::MatchStartsWith); - if (profile.isEmpty()) return; - mDataFilesModel->uncheckAll(); QStringList masters = mLauncherSettings.values(QString("Profiles/") + profile + QString("/master"), Qt::MatchExactly); QStringList plugins = mLauncherSettings.values(QString("Profiles/") + profile + QString("/plugin"), Qt::MatchExactly); - qDebug() << "masters to check " << plugins; foreach (const QString &master, masters) { QModelIndex index = mDataFilesModel->indexFromItem(mDataFilesModel->findItem(master)); @@ -316,21 +306,23 @@ void DataFilesPage::saveSettings() mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), profile); } - qDebug() << "save settings" << profile; mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); + mGameSettings.remove(QString("master")); + mGameSettings.remove(QString("plugin")); + QStringList items = mDataFilesModel->checkedItems(); foreach(const QString &item, items) { if (item.endsWith(QString(".esm"), Qt::CaseInsensitive)) { - qDebug() << "setting " << item; mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/master"), item); + mGameSettings.setMultiValue(QString("master"), item); } else if (item.endsWith(QString(".esp"), Qt::CaseInsensitive)) { - qDebug() << "setting " << item; mLauncherSettings.setMultiValue(QString("Profiles/") + profile + QString("/plugin"), item); + mGameSettings.setMultiValue(QString("plugin"), item); } } @@ -500,7 +492,6 @@ void DataFilesPage::filterChanged(const QString filter) void DataFilesPage::profileChanged(const QString &previous, const QString ¤t) { - qDebug() << "Profile is changed from: " << previous << " to " << current; // Prevent the deletion of the default profile if (current == QLatin1String("Default")) { mDeleteProfileAction->setEnabled(false); @@ -527,7 +518,6 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre void DataFilesPage::profileRenamed(const QString &previous, const QString ¤t) { - qDebug() << "rename"; if (previous.isEmpty()) return; @@ -577,7 +567,6 @@ void DataFilesPage::showContextMenu(const QPoint &point) : mCheckAction->setEnabled(true); } - // Show menu mContextMenu->exec(globalPos); diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index 717ce6e87..8aac1552d 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -29,6 +29,18 @@ public: mSettings.insert(key, value); } + inline void setMultiValue(const QString &key, const QString &value) + { + QStringList values = mSettings.values(key); + if (!values.contains(value)) + mSettings.insertMulti(key, value); + } + + inline void remove(const QString &key) + { + mSettings.remove(key); + } + inline QStringList getDataDirs() { return mDataDirs; } inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } inline QString getDataLocal() {return mDataLocal; } diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 361884da6..e70bc0d72 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -32,15 +32,10 @@ public: inline void setMultiValue(const QString &key, const QString &value) { QStringList values = mSettings.values(key); - if (!values.contains(value)) { - qDebug() << "inserting " << value; + if (!values.contains(value)) mSettings.insertMulti(key, value); - } else { - qDebug() << "not inserting " << value; - } } - inline void remove(const QString &key) { mSettings.remove(key); From 6cceb04adf93e3328c478127a635d13b3b605e93 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Feb 2013 03:08:00 +0100 Subject: [PATCH 663/916] When a custom near clip plane is used, we need to fix up a second viewproj matrix manually to get proper depth values in the vertex shader. This fixes fog on reflections. --- apps/openmw/mwrender/refraction.cpp | 11 +++++++- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 6 +++++ files/materials/objects.shader | 33 +++++++++++++++++++++-- files/materials/openmw.configuration | 7 ++++- files/materials/terrain.shader | 24 +++++++++++++++++ 6 files changed, 79 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index a924be7d7..67fe9e340 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "renderconst.hpp" namespace MWRender @@ -30,7 +32,7 @@ namespace MWRender vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); - vp->setMaterialScheme("water_reflection"); + vp->setMaterialScheme("water_refraction"); vp->setBackgroundColour (Ogre::ColourValue(0.0078, 0.0576, 0.150)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); @@ -54,6 +56,12 @@ namespace MWRender mCamera->setAspectRatio(mParentCamera->getAspectRatio()); mCamera->setFOVy(mParentCamera->getFOVy()); + // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. + // since all we are interested in is depth, we only need the third row of the matrix. + Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); + sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); + sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); + // enable clip plane here to take advantage of CPU culling for overwater or underwater objects mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); @@ -62,6 +70,7 @@ namespace MWRender void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) { + mCamera->disableCustomNearClipPlane (); mRenderActive = false; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6c6c47417..c4f2d99cb 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -140,6 +140,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); + sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); + sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); applyCompositors(); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f71431a27..a76b0d1d3 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -144,6 +144,12 @@ void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) mSky->setSkyPosition(pos); mCamera->enableReflection(mWaterPlane); + // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. + // since all we are interested in is depth, we only need the third row of the matrix. + Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); + sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); + sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); + // enable clip plane here to take advantage of CPU culling for overwater or underwater objects mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); } diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 3f5aa418f..fad8c1ac8 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -23,12 +23,21 @@ #define VERTEX_LIGHTING 1 +#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) + #ifdef SH_VERTEX_SHADER // ------------------------------------- VERTEX --------------------------------------- SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + +#if VIEWPROJ_FIX + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) + shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) + shUniform(float4x4, vpMatrix) @shAutoConstant(vpMatrix, viewproj_matrix) +#endif + shVertexInput(float2, uv0) shOutput(float2, UV) shNormalInput(float4) @@ -65,7 +74,6 @@ #if SHADOWS shOutput(float4, lightSpacePos0) shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) #endif #if SHADOWS_PSSM @@ -73,7 +81,9 @@ shOutput(float4, lightSpacePos@shIterator) shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) @shEndForeach - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#if !VIEWPROJ_FIX + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif #endif #if VERTEX_LIGHTING @@ -89,9 +99,28 @@ #endif #ifdef NEED_DEPTH + + +#if VIEWPROJ_FIX + float4x4 vpFixed = vpMatrix; +#if !SH_GLSL + vpFixed[2] = vpRow2Fix; +#else + vpFixed[0][2] = vpRow2Fix.x; + vpFixed[1][2] = vpRow2Fix.y; + vpFixed[2][2] = vpRow2Fix.z; + vpFixed[3][2] = vpRow2Fix.w; +#endif + + float4x4 fixedWVP = shMatrixMult(vpFixed, worldMatrix); + + depthPassthrough = shMatrixMult(fixedWVP, shInputPosition).z; +#else depthPassthrough = shOutputPosition.z; #endif +#endif + #if LIGHTING objSpacePositionPassthrough = shInputPosition.xyz; #endif diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index 870c96728..21ac9416b 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -1,8 +1,13 @@ configuration water_reflection { - fog false shadows false shadows_pssm false + viewproj_fix true +} + +configuration water_refraction +{ + viewproj_fix true } configuration local_map diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 497463f8e..b7ee15e8d 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -23,6 +23,8 @@ #define UNDERWATER @shGlobalSettingBool(underwater_effects) && LIGHTING +#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) + #if NEED_DEPTH @shAllocatePassthrough(1, depth) @@ -51,6 +53,10 @@ shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) shUniform(float4x4, viewProjMatrix) @shAutoConstant(viewProjMatrix, viewproj_matrix) +#if VIEWPROJ_FIX + shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) +#endif + shUniform(float2, lodMorph) @shAutoConstant(lodMorph, custom, 1001) shVertexInput(float2, uv0) @@ -94,7 +100,25 @@ shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); #if NEED_DEPTH +#if VIEWPROJ_FIX + float4x4 vpFixed = viewProjMatrix; +#if !SH_GLSL + vpFixed[2] = vpRow2Fix; +#else + vpFixed[0][2] = vpRow2Fix.x; + vpFixed[1][2] = vpRow2Fix.y; + vpFixed[2][2] = vpRow2Fix.z; + vpFixed[3][2] = vpRow2Fix.w; +#endif + + float4x4 fixedWVP = shMatrixMult(vpFixed, worldMatrix); + + float depth = shMatrixMult(fixedWVP, shInputPosition).z; + @shPassthroughAssign(depth, depth); +#else @shPassthroughAssign(depth, shOutputPosition.z); +#endif + #endif @shPassthroughAssign(UV, uv0); From 427152c518aa9c4ffef873772dcc254a9fb44204 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Feb 2013 03:15:31 +0100 Subject: [PATCH 664/916] Disabled ripples until we can properly trigger them from the new character controller. --- apps/openmw/mwrender/water.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index a76b0d1d3..f0680f208 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -393,10 +393,9 @@ void Water::update(float dt, Ogre::Vector3 player) mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - /// \todo player.y is the scene node position (which is above the head) and not the feet position //if (player.y <= mTop) { - mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); + //mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); From 5d403ebdd34ec1c616c4221b5af04a35261662ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Feb 2013 04:03:24 +0100 Subject: [PATCH 665/916] Fix collision debug drawer (tcg) --- apps/openmw/mwworld/worldimp.cpp | 4 ++++ libs/openengine/bullet/BtOgreExtras.h | 2 +- libs/openengine/bullet/physic.cpp | 14 ++++++++------ libs/openengine/bullet/physic.hpp | 9 +++++++++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f2d2e2c00..a80f083b5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -186,6 +186,8 @@ namespace MWWorld mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine); + mPhysEngine->setSceneManager(renderer.getScene()); + mWeatherManager = new MWWorld::WeatherManager(mRendering); int idx = 0; @@ -892,6 +894,8 @@ namespace MWWorld Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } + // the only purpose this has currently is to update the debug drawer + mPhysEngine->stepSimulation (duration); } bool World::toggleCollisionMode() diff --git a/libs/openengine/bullet/BtOgreExtras.h b/libs/openengine/bullet/BtOgreExtras.h index 423924eda..b20a3ff98 100644 --- a/libs/openengine/bullet/BtOgreExtras.h +++ b/libs/openengine/bullet/BtOgreExtras.h @@ -207,7 +207,7 @@ public: mLineDrawer->setMaterial("BtOgre/DebugLines"); - mLineDrawer->setVisibilityFlags (1024); + //mLineDrawer->setVisibilityFlags (1024); } ~DebugDrawer() diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7ffe07189..220ba5d51 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -191,10 +191,7 @@ namespace Physic { if(!isDebugCreated) { - Ogre::SceneManagerEnumerator::SceneManagerIterator iter = Ogre::Root::getSingleton().getSceneManagerIterator(); - iter.begin(); - Ogre::SceneManager* scn = iter.getNext(); - Ogre::SceneNode* node = scn->getRootSceneNode()->createChildSceneNode(); + Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); node->pitch(Ogre::Degree(-90)); mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld); dynamicsWorld->setDebugDrawer(mDebugDrawer); @@ -219,6 +216,11 @@ namespace Physic return mDebugActive; } + void PhysicEngine::setSceneManager(Ogre::SceneManager* sceneMgr) + { + mSceneMgr = sceneMgr; + } + PhysicEngine::~PhysicEngine() { HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); @@ -471,7 +473,8 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { - dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + // This isn't needed as there are no dynamic objects at this point + //dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); if(isDebugCreated) { mDebugDrawer->step(); @@ -494,7 +497,6 @@ namespace Physic void PhysicEngine::removeCharacter(const std::string &name) { - //std::cout << "remove"; PhysicActorContainer::iterator it = PhysicActorMap.find(name); if (it != PhysicActorMap.end() ) { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 1a28023a9..559bf032e 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -24,6 +24,11 @@ namespace BtOgre class DebugDrawer; } +namespace Ogre +{ + class SceneManager; +} + namespace MWWorld { class World; @@ -269,6 +274,8 @@ namespace Physic void getObjectAABB(const std::string &mesh, float scale, btVector3 &min, btVector3 &max); + void setSceneManager(Ogre::SceneManager* sceneMgr); + /** * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). */ @@ -305,6 +312,8 @@ namespace Physic typedef std::map PhysicActorContainer; PhysicActorContainer PhysicActorMap; + Ogre::SceneManager* mSceneMgr; + //debug rendering BtOgre::DebugDrawer* mDebugDrawer; bool isDebugCreated; From 17200cb226a8ea95a940e7093f14170098b80d34 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 20:43:55 -0800 Subject: [PATCH 666/916] Don't try to move when there's no speed --- apps/openmw/mwmechanics/character.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 27bc62d07..00a58523d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -185,7 +185,7 @@ Ogre::Vector3 CharacterController::update(float duration) bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); - if(std::abs(vec.x/2.0f) > std::abs(vec.y)) + if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { if(vec.x > 0.0f) setState(isrunning ? @@ -198,7 +198,7 @@ Ogre::Vector3 CharacterController::update(float duration) // Apply any forward/backward movement manually movement.y += vec.y * (speed*duration); } - else if(vec.y != 0.0f) + else if(vec.y != 0.0f && speed > 0.0f) { if(vec.y > 0.0f) setState(isrunning ? From 5a1a0b7338f9c4f8bafb2b65d82c649c95c12a65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 18 Feb 2013 22:39:43 -0800 Subject: [PATCH 667/916] Add and use an MWWorld::isFlying method --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 11 +++++++++++ apps/openmw/mwworld/worldimp.hpp | 1 + libs/openengine/bullet/physic.cpp | 5 ----- libs/openengine/bullet/physic.hpp | 6 +++++- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index da670cf23..cc23e035e 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -286,6 +286,7 @@ namespace MWBase virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; + virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d135d2683..998b90e19 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -336,7 +336,7 @@ namespace MWClass float moveSpeed; if(normalizedEncumbrance > 1.0f) moveSpeed = 0.0f; - else if(0/*world->isFlying(ptr)*/) + else if(world->isFlying(ptr)) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + 0.0f/*levitationBonus*/); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a80f083b5..1a6630232 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1382,6 +1382,17 @@ namespace MWWorld mRendering->getTriangleBatchCount(triangles, batches); } + bool + World::isFlying(const MWWorld::Ptr &ptr) const + { + RefData &refdata = ptr.getRefData(); + /// \todo check for levitation effects + const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); + if(physactor && physactor->getCollisionMode()) + return false; + return true; + } + bool World::isSwimming(const MWWorld::Ptr &object) const { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8b9b39617..d347570fe 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -314,6 +314,7 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); + virtual bool isFlying(const MWWorld::Ptr &ptr) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 220ba5d51..e5045eee6 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -54,11 +54,6 @@ namespace Physic collisionMode = collision; } - bool PhysicActor::getCollisionMode() - { - return collisionMode; - } - void PhysicActor::setRotation(const Ogre::Quaternion &quat) { diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 559bf032e..8ea9657e6 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -78,7 +78,11 @@ namespace Physic void enableCollisions(bool collision); - bool getCollisionMode(); + bool getCollisionMode() const + { + return collisionMode; + } + /** * This returns the visual position of the PhysicActor (used to position a scenenode). From c694161272e61abecd4c429a59c90b8cc05cc03b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 01:28:02 -0800 Subject: [PATCH 668/916] Don't try to step if not on the ground --- apps/openmw/mwworld/physicssystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 058160595..dc290ec28 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -156,7 +156,8 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(!stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + if(!onground || + !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); resultantDirection.normalise(); From 8255a64bfe9038f0aae9df3925ff3f9e6c7c827d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 02:10:36 -0800 Subject: [PATCH 669/916] Handle levitate and swift swim effects --- apps/openmw/mwclass/npc.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 998b90e19..4a31334ad 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -322,6 +322,8 @@ namespace MWClass { const MWBase::World *world = MWBase::Environment::get().getWorld(); const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); + const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr); float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified()* @@ -330,16 +332,17 @@ namespace MWClass walkSpeed = std::max(0.0f, walkSpeed); if(Npc::getStance(ptr, Sneak, false)) walkSpeed *= fSneakSpeedMultiplier->getFloat(); + float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); float moveSpeed; - if(normalizedEncumbrance > 1.0f) + if(normalizedEncumbrance >= 1.0f) moveSpeed = 0.0f; else if(world->isFlying(ptr)) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + - 0.0f/*levitationBonus*/); + mageffects.get(MWMechanics::EffectKey(10)).mMagnitude/*levitate*/); flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); @@ -350,7 +353,7 @@ namespace MWClass float swimSpeed = walkSpeed; if(Npc::getStance(ptr, Run, false)) swimSpeed = runSpeed; - swimSpeed *= 1.0f + 0.01f * 0.0f/*swiftSwimBonus*/; + swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1)).mMagnitude/*swift swim*/; swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; From a510adc57279f227cfa26af7b45df2921556236c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 02:25:57 -0800 Subject: [PATCH 670/916] Allow stepping when not being affected by gravity --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index dc290ec28..63f9cb949 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -156,7 +156,7 @@ namespace MWWorld //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) { - if(!onground || + if((gravity && !onground) || !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); From 1399a06c76708c438ea4a3f47a59f267be84c7ec Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:01:33 -0800 Subject: [PATCH 671/916] Update animation looping when setting the same state --- apps/openmw/mwmechanics/character.cpp | 4 ++++ apps/openmw/mwrender/animation.cpp | 5 +++++ apps/openmw/mwrender/animation.hpp | 2 ++ 3 files changed, 11 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 00a58523d..713f1bb3b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -260,7 +260,11 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) + { + if(mAnimation) + mAnimation->setLooping(loop); return; + } mState = state; if(!mAnimation) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1a606992a..da91af005 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,6 +169,11 @@ void Animation::setSpeed(float speed) mAnimSpeedMult = speed / mAnimVelocity; } +void Animation::setLooping(bool loop) +{ + mLooping = loop; +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index fc35c06be..2f930e9ad 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -76,6 +76,8 @@ public: void setSpeed(float speed); + void setLooping(bool loop); + void play(const std::string &groupname, const std::string &start, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; From 89fabdb3a935a9512df98d91cbe20fabc24332cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:18:15 -0800 Subject: [PATCH 672/916] Update the PhysicActor's RigidBody when moving This works, but is less than ideal. As it is now, the rigid body gets updated twice as the position and rotation are set separately. They should instead be updated together. --- apps/openmw/mwworld/physicssystem.cpp | 4 ++++ libs/openengine/bullet/physic.cpp | 7 +++++++ libs/openengine/bullet/physic.hpp | 2 ++ 3 files changed, 13 insertions(+) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 63f9cb949..ec867326d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -414,6 +414,10 @@ namespace MWWorld mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); } } + else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) + { + physact->setPosition(position); + } } void PhysicsSystem::rotateObject (const Ptr& ptr) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index e5045eee6..4a1c33fb8 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -55,6 +55,12 @@ namespace Physic } + void PhysicActor::setPosition(const Ogre::Vector3 &pos) + { + if(pos != getPosition()) + mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); + } + void PhysicActor::setRotation(const Ogre::Quaternion &quat) { if(!quat.equals(getRotation(), Ogre::Radian(0))){ @@ -62,6 +68,7 @@ namespace Physic } } + Ogre::Vector3 PhysicActor::getPosition() { btVector3 vec = mBody->getWorldTransform().getOrigin(); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 8ea9657e6..bd5d3d50a 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -69,6 +69,8 @@ namespace Physic ~PhysicActor(); + void setPosition(const Ogre::Vector3 &pos); + /** * This adjusts the rotation of a PhysicActor * If we have any problems with this (getting stuck in pmove) we should change it From 5d55b41714dfec738b71f5a0c0988d6021b9cb27 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 04:59:38 -0800 Subject: [PATCH 673/916] Remove a now-unneeded(?) hack --- apps/openmw/mwworld/physicssystem.cpp | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index ec867326d..5552bd749 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -394,30 +394,13 @@ namespace MWWorld void PhysicsSystem::moveObject (const Ptr& ptr) { - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - std::string handle = node->getName(); - Ogre::Vector3 position = node->getPosition(); - if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) - { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 - - - if(dynamic_cast(body->getCollisionShape()) == NULL){ - btTransform tr = body->getWorldTransform(); - tr.setOrigin(btVector3(position.x,position.y,position.z)); - body->setWorldTransform(tr); - } - else{ - //For objects that contain a box shape. - //Do any such objects exist? Perhaps animated objects? - mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); - } - } + Ogre::SceneNode *node = ptr.getRefData().getBaseNode(); + const std::string &handle = node->getName(); + const Ogre::Vector3 &position = node->getPosition(); + if(OEngine::Physic::RigidBody *body = mEngine->getRigidBody(handle)) + body->getWorldTransform().setOrigin(btVector3(position.x,position.y,position.z)); else if(OEngine::Physic::PhysicActor *physact = mEngine->getCharacter(handle)) - { physact->setPosition(position); - } } void PhysicsSystem::rotateObject (const Ptr& ptr) From f8349a04bf95033b8ba4119f460cedb8216c16c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 05:26:58 -0800 Subject: [PATCH 674/916] Use the looping portion of the animation to calculate the velocity --- apps/openmw/mwrender/animation.cpp | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index da91af005..d63e30247 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -284,12 +284,32 @@ void Animation::play(const std::string &groupname, const std::string &start, boo if(track && track->getNumKeyFrames() > 1) { - const Ogre::TransformKeyFrame *startkf, *endkf; - startkf = static_cast(track->getKeyFrame(0)); - endkf = static_cast(track->getKeyFrame(track->getNumKeyFrames() - 1)); + float loopstarttime = 0.0f; + float loopstoptime = mCurrentAnim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); + while(keyiter != mCurrentKeys->end()) + { + if(keyiter->second == "loop start") + loopstarttime = keyiter->first; + else if(keyiter->second == "loop stop") + { + loopstoptime = keyiter->first; + break; + } + keyiter++; + } - mAnimVelocity = startkf->getTranslate().distance(endkf->getTranslate()) / - mCurrentAnim->getLength(); + if(loopstoptime > loopstarttime) + { + Ogre::TransformKeyFrame startkf(0, loopstarttime); + Ogre::TransformKeyFrame endkf(0, loopstoptime); + + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + + mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); + } } } From 8196694c08580aece938d644f2f011ad17a08584 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 06:04:25 -0800 Subject: [PATCH 675/916] Avoid applying the animation when resetting it --- apps/openmw/mwrender/animation.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d63e30247..330045423 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -228,8 +228,8 @@ Ogre::Vector3 Animation::updatePosition(float time) posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ - mAccumRoot->translate(-posdiff); mLastPosition += posdiff; + mAccumRoot->setPosition(-mLastPosition); } return posdiff; } @@ -247,12 +247,24 @@ void Animation::reset(const std::string &marker) mNextKey = mCurrentKeys->begin(); mCurrentTime = 0.0f; } - applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); if(mNonAccumRoot) { - mLastPosition = mNonAccumRoot->getPosition() * mAccumulate; - mAccumRoot->setPosition(-mLastPosition); + const Ogre::NodeAnimationTrack *track = 0; + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track) + { + Ogre::TransformKeyFrame kf(0, mCurrentTime); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); + mLastPosition = kf.getTranslate() * mAccumulate; + } } } From 86f6491bc8e15782e23f369bf1ff6c0453b04f1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 06:38:48 -0800 Subject: [PATCH 676/916] Remove unused pmove code --- CMakeLists.txt | 2 - libs/openengine/bullet/physic.cpp | 1 - libs/openengine/bullet/pmove.cpp | 2115 ----------------------------- libs/openengine/bullet/pmove.h | 206 --- libs/openengine/bullet/trace.cpp | 3 - libs/openengine/bullet/trace.h | 4 - 6 files changed, 2331 deletions(-) delete mode 100644 libs/openengine/bullet/pmove.cpp delete mode 100644 libs/openengine/bullet/pmove.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cfd1c7dd3..fac7bb41e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,8 +94,6 @@ set(OENGINE_BULLET ${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.h - ${LIBDIR}/openengine/bullet/pmove.cpp - ${LIBDIR}/openengine/bullet/pmove.h ${LIBDIR}/openengine/bullet/trace.cpp ${LIBDIR}/openengine/bullet/trace.h diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 4a1c33fb8..5d5749d5d 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -2,7 +2,6 @@ #include #include #include -#include "pmove.h" #include #include "CMotionState.h" #include "OgreRoot.h" diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp deleted file mode 100644 index 9cd76968a..000000000 --- a/libs/openengine/bullet/pmove.cpp +++ /dev/null @@ -1,2115 +0,0 @@ -/* -This source file is a *modified* version of bg_pmove.c from the Quake 3 Arena source code, -which was released under the GNU GPL (v2) in 2005. -Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. -*/ - - -#include "pmove.h" - -//#include "bprintf.h" - -//#include "..\..\ESMParser\ESMParser\CELL.h" - -//#include "GameTime.h" - -//#include "Sound.h" - -//#include "..\..\ESMParser\ESMParser\SNDG.h" -//#include "..\..\ESMParser\ESMParser\SOUN.h" - -#include - -#include "trace.h" - -//SceneInstance* global_lastscene = NULL; - -// Forward declaration: -void PM_AirMove(); - -static playerMove* pm = NULL; - -//extern std::map ExtCellLookup; - -static struct playermoveLocal -{ - playermoveLocal() : frametime(1.0f / 20.0f), groundPlane(true), walking(true), msec(50) - { - forward = Ogre::Vector3(0.0f, 0.0f, 0.0f); - right = Ogre::Vector3(0.0f, 0.0f, 0.0f); - up = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - previous_origin = Ogre::Vector3(0.0f, 0.0f, 0.0f); - previous_velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - } - - traceResults groundTrace; - - //SceneInstance* scene; - - float frametime; // in seconds (usually something like 0.01f) - float impactSpeed; - - Ogre::Vector3 forward; - Ogre::Vector3 right; - Ogre::Vector3 up; - - int msec; - - Ogre::Vector3 previous_origin, previous_velocity; - - int previous_waterlevel; // the waterlevel before this pmove - - bool groundPlane; // if we're standing on a groundplane this frame - - bool walking; - int waterHeight; - bool hasWater; - bool isInterior; - -} pml; - -static inline void PM_ClipVelocity(const Ogre::Vector3& in, const Ogre::Vector3& normal, Ogre::Vector3& out, const float overbounce) -{ - float backoff; - //float change; - //int i; - - // backoff = in dot normal - //backoff = DotProduct (in, normal); - backoff = in.dotProduct(normal); - - if ( backoff < 0 ) - backoff *= overbounce; - else - backoff /= overbounce; - - // change = normal * backoff - // out = in - change - /*for ( i=0 ; i<3 ; i++ ) - { - change = normal[i]*backoff; - out[i] = in[i] - change; - - }*/ - float changex = normal.x * backoff; - out.x = in.x - changex; - float changey = normal.y * backoff; - out.y = in.y - changey; - float changez = normal.z * backoff; - out.z = in.z - changez; -} - -float VectorNormalize2( const Ogre::Vector3& v, Ogre::Vector3& out) -{ - float length, ilength; - - length = v.x * v.x+ v.y * v.y + v.z * v.z; - length = sqrt(length); - - if (length) - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) ); -#endif - ilength = 1 / length; - out.x= v.x * ilength; - out.y = v.y * ilength; - out.z = v.z * ilength; - } else - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])==0.0f) && (Q_fabs(v[1])==0.0f) && (Q_fabs(v[2])==0.0f)) ); -#endif - //VectorClear( out ); - out.x = 0; out.y = 0; out.z = 0; - } - - return length; - -} - - -float VectorNormalize(Ogre::Vector3& out) -{ - float length, ilength; - - length = out.x * out.x + out.y * out.y + out.z * out.z; - length = sqrt(length); - - if (length) - { -#ifndef Q3_VM // bk0101022 - FPE related -// assert( ((Q_fabs(v[0])!=0.0f) || (Q_fabs(v[1])!=0.0f) || (Q_fabs(v[2])!=0.0f)) ); -#endif - ilength = 1 / length; - out.x = out.x * ilength; - out.y = out.y * ilength; - out.z = out.z * ilength; - } - - return length; - -} - -/* -================== -PM_SlideMove - -Returns qtrue if the velocity was clipped in some way -================== -*/ - -bool PM_SlideMove( bool gravity ) -{ - int bumpcount, numbumps; - Ogre::Vector3 dir; - float d; - int numplanes; - Ogre::Vector3 planes[MAX_CLIP_PLANES]; - Ogre::Vector3 primal_velocity; - Ogre::Vector3 clipVelocity; - int i, j, k; - struct traceResults trace; - Ogre::Vector3 end(0,0,0); - float time_left; - float into; - Ogre::Vector3 endVelocity(0,0,0); - Ogre::Vector3 endClipVelocity(0,0,0); - - numbumps = 4; - - // primal_velocity = pm->ps->velocity - //VectorCopy (pm->ps->velocity, primal_velocity); - primal_velocity = pm->ps.velocity; - - if ( gravity ) - { - // endVelocity = pm->ps->velocity - vec3(0, 0, pm->ps->gravity * pml.frametime) - //VectorCopy( pm->ps->velocity, endVelocity ); - endVelocity = pm->ps.velocity; - //endVelocity[2] -= pm->ps->gravity * pml.frametime; - endVelocity.z -= pm->ps.gravity * pml.frametime; - - // pm->ps->velocity = avg(pm->ps->velocity.z, endVelocity.z) - //pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; - pm->ps.velocity.z= (pm->ps.velocity.z + endVelocity.z) * 0.5f; - - //primal_velocity[2] = endVelocity[2]; - primal_velocity.z = endVelocity.z; - - if ( pml.groundPlane ) - // slide along the ground plane - //PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP); - } - - time_left = pml.frametime; - - // never turn against the ground plane - if ( pml.groundPlane ) - { - numplanes = 1; - - // planes[0] = pml.groundTrace.plane.normal - //VectorCopy( pml.groundTrace.plane.normal, planes[0] ); - planes[0] = pml.groundTrace.planenormal; - } else - numplanes = 0; - - // never turn against original velocity - VectorNormalize2( pm->ps.velocity, planes[numplanes] ); - numplanes++; - - for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) - { - - // calculate position we are trying to move to - //VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); - end = pm->ps.origin + pm->ps.velocity * time_left; - - // see if we can make it there - //pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemaskg); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&(end), *(const D3DXVECTOR3* const)&(pm->ps.velocity), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, end, pm->ps.halfExtents, Ogre::Math::DegreesToRadians (pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - if (trace.allsolid) - { - // entity is completely trapped in another solid - //pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - - if (trace.fraction > 0) - // actually covered some distance - //VectorCopy (trace.endpos, pm->ps->origin); - pm->ps.origin = trace.endpos; - - if (trace.fraction == 1) - break; // moved the entire distance - - // save entity for contact8 - //PM_AddTouchEnt( trace.entityNum ); - - time_left -= time_left * trace.fraction; - - if (numplanes >= MAX_CLIP_PLANES) - { - // this shouldn't really happen - //VectorClear( pm->ps->velocity ); - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - - // - // if this is the same plane we hit before, nudge velocity - // out along it, which fixes some epsilon issues with - // non-axial planes - // - for ( i = 0 ; i < numplanes ; i++ ) - { - if (trace.planenormal.dotProduct(planes[i]) > 0.99) //OGRE::VECTOR3 ? - //if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) - { - // pm->ps->velocity += (trace.plane.normal + pm->ps->velocity) - //VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); - pm->ps.velocity = trace.planenormal + pm->ps.velocity; - break; - } - } - - if ( i < numplanes ) - continue; - - //VectorCopy (trace.plane.normal, planes[numplanes]); - planes[numplanes] = trace.planenormal; - numplanes++; - - // - // modify velocity so it parallels all of the clip planes - // - - // find a plane that it enters - for ( i = 0 ; i < numplanes ; i++ ) - { - //into = DotProduct( pm->ps->velocity, planes[i] ); - into = pm->ps.velocity.dotProduct(planes[i]); - if ( into >= 0.1 ) - continue; // move doesn't interact with the plane - - - if(planes[i].x >= .70) - { - pm->ps.velocity.z = 0; - return true; - } - // see how hard we are hitting things - if ( -into > pml.impactSpeed ) - pml.impactSpeed = -into; - - // slide along the plane - //PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, planes[i], clipVelocity, OVERCLIP); - - // slide along the plane - PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); - - // see if there is a second plane that the new move enters - for ( j = 0 ; j < numplanes ; j++ ) - { - if ( j == i ) - continue; - - if (clipVelocity.dotProduct(planes[j]) >= 0.1) - //if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) - continue; // move doesn't interact with the plane - - - - - //pm->ps.velocity = Ogre::Vector3(0,0,0); - //return true; - - - // try clipping the move to the plane - PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); - PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); - - // see if it goes back into the first clip plane - if (clipVelocity.dotProduct(planes[i]) >= 0) - //if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) - continue; - - - // slide the original velocity along the crease - //dProduct (planes[i], planes[j], dir); - dir = planes[i].crossProduct(planes[j]) ; - - //VectorNormalize( dir ); - //D3DXVec3Normalize( (D3DXVECTOR3* const)&dir, (const D3DXVECTOR3* const)&dir); - VectorNormalize(dir); - - //d = DotProduct( dir, pm->ps->velocity ); - d = dir.dotProduct(pm->ps.velocity); - - //VectorScale( dir, d, clipVelocity ); - clipVelocity = dir * d; - - //CrossProduct (planes[i], planes[j], dir); - dir = planes[i].crossProduct(planes[j]) ; - - - //VectorNormalize( dir ); - //D3DXVec3Normalize( (D3DXVECTOR3* const)&dir, (const D3DXVECTOR3* const)&dir); - VectorNormalize(dir); - - //d = DotProduct( dir, endVelocity ); - d = dir.dotProduct(endVelocity); - - //VectorScale( dir, d, endClipVelocity ); - endClipVelocity = dir * d; - - // see if there is a third plane the the new move enters - for ( k = 0 ; k < numplanes ; k++ ) - { - - if ( k == i || k == j ) - continue; - - if (clipVelocity.dotProduct(planes[k]) >= 0.1) - //if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) - continue; // move doesn't interact with the plane - - // stop dead at a tripple plane interaction - //VectorClear( pm->ps->velocity ); - //printf("Stop dead at a triple plane interaction\n"); - pm->ps.velocity = Ogre::Vector3(0,0,0); - return true; - } - } - - // if we have fixed all interactions, try another move - //VectorCopy( clipVelocity, pm->ps->velocity ); - pm->ps.velocity = clipVelocity; - - //VectorCopy( endClipVelocity, endVelocity ); - endVelocity = endClipVelocity; - break; - } - } - - if ( gravity ) - //VectorCopy( endVelocity, pm->ps->velocity ); - pm->ps.velocity = endVelocity; - - // don't change velocity if in a timer (FIXME: is this correct?) - if ( pm->ps.pm_time ) - //VectorCopy( primal_velocity, pm->ps->velocity ); - pm->ps.velocity = primal_velocity; - - //return ( (qboolean)(bumpcount != 0) ); - return bumpcount != 0; -} - -/* -================== -PM_StepSlideMove - -================== -*/ -int PM_StepSlideMove( bool gravity ) -{ - Ogre::Vector3 start_o, start_v; - Ogre::Vector3 down_o, down_v; - traceResults trace; -// float down_dist, up_dist; -// vec3_t delta, delta2; - Ogre::Vector3 up, down; - float stepSize; - - //std::cout << "StepSlideMove\n"; - // start_o = pm->ps->origin - //VectorCopy (pm->ps->origin, start_o); - start_o = pm->ps.origin; - - // start_v = pm->ps->velocity - //VectorCopy (pm->ps->velocity, start_v); - start_v = pm->ps.velocity; - - if ( PM_SlideMove( gravity ) == false ) - return 1; // we got exactly where we wanted to go first try - - - // down = start_o - vec3(0, 0, STEPSIZE) - //VectorCopy(start_o, down); - down = start_o; - down.z -= STEPSIZE; - - //pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, start_o, down, , 0, pml.scene); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, down, start_o, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - // up = vec3(0, 0, 1) - //VectorSet(up, 0, 0, 1); - up = Ogre::Vector3(0.0f, 0.0f, 1.0f); - - // never step up when you still have up velocity - //if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || DotProduct(trace.plane.normal, up) < 0.7)) - if (pm->ps.velocity.z > 0 && ( - trace.fraction == 1.0 || trace.planenormal.dotProduct(up) < 0.7 - ) ) - return 2; - - // down_o = pm->ps->origin - //VectorCopy (pm->ps->origin, down_o); - down_o = pm->ps.origin; - - // down_v = pm->ps->velocity - //VectorCopy (pm->ps->velocity, down_v); - down_v = pm->ps.velocity; - - // up = start_o + vec3(0, 0, STEPSIZE) - //VectorCopy (start_o, up); - up = start_o; - //up[2] += STEPSIZE; - up.z += STEPSIZE; - - // test the player position if they were a stepheight higher - //pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&up, D3DXVECTOR3(0.0f, STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, start_o, up, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( trace.allsolid ) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:bend can't step\n", c_pmove); - //bprintf("bend can't step\n"); - return 3; // can't step up - } - - //stepSize = trace.endpos[2] - start_o[2]; - stepSize = trace.endpos.z - start_o.z; - - // try slidemove from this position - //VectorCopy (trace.endpos, pm->ps->origin); // pm->ps->origin = trace.endpos - pm->ps.origin = trace.endpos; - //VectorCopy (start_v, pm->ps->velocity); // pm->ps->velocity = start_v - pm->ps.velocity = start_v; - - PM_SlideMove( gravity ); - - // push down the final amount - - // down = pm->ps->origin - vec3(0, 0, stepSize) - //VectorCopy (pm->ps->origin, down); - down = pm->ps.origin; - //down[2] -= stepSize; - down.z -= stepSize; - - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, down, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - if ( !trace.allsolid ) - //VectorCopy (trace.endpos, pm->ps->origin); - pm->ps.origin = trace.endpos; - - if ( trace.fraction < 1.0 ) - //PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, trace.planenormal, pm->ps.velocity, OVERCLIP); - - { - // use the step move - float delta; - - //delta = pm->ps->origin[2] - start_o[2]; - delta = pm->ps.origin.z - start_o.z; - if ( delta > 2 ) - { - pm->ps.counter = 10; - - /* - if (gravity) - printf("g on: %f ", delta); - else - printf("g off: %f ", delta); - - if ( delta < 7 ) - printf("stepped 3 < x < 7\n"); - //PM_AddEvent( EV_STEP_4 ); - else if ( delta < 11 ) - printf("stepped 7 < x < 11\n"); - //PM_AddEvent( EV_STEP_8 ); - else if ( delta < 15 ) - printf("stepped 11 < x < 15\n"); - //PM_AddEvent( EV_STEP_12 ); - else - printf("stepped 15+\n"); - //PM_AddEvent( EV_STEP_16 ); - */ - } - /*if ( pm->debugLevel ) - Com_Printf("%i:stepped\n", c_pmove);*/ - } - - return 4; -} - -void PM_Friction(void) -{ - - Ogre::Vector3 vec; - float* vel; - float speed, newspeed, control; - float drop; - - vel = &(pm->ps.velocity.x); - - // vec = vel - //VectorCopy( vel, vec ); - vec = pm->ps.velocity; - - if ( pml.walking ) - //vec[2] = 0; // ignore slope movement - vec.z = 0; - - //speed = VectorLength(vec); - speed = vec.length(); - if (speed < 1) - { - vel[0] = 0; - vel[1] = 0; // allow sinking underwater - // FIXME: still have z friction underwater? - //bprintf("Static friction (vec = [%f, %f, %f]) (vec.length = %f)\n", vec.x, vec.y, vec.z, speed); - return; - } - - drop = 0; - - // apply ground friction - if ( pm->ps.waterlevel <= 1 ) - { - if ( pml.walking )//&& !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) - { - // if getting knocked back, no friction - //if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) - { - control = (speed < pm_stopspeed) ? pm_stopspeed : speed; - drop += control * pm_friction * pml.frametime; - } - } - } - - // apply water friction even if just wading - if ( pm->ps.waterlevel ) - drop += speed * pm_waterfriction * pm->ps.waterlevel * pml.frametime; - - // apply flying friction - /*if ( pm->ps->powerups[PW_FLIGHT]) - drop += speed * pm_flightfriction * pml.frametime; - - if ( pm->ps->pm_type == PM_SPECTATOR) - drop += speed * pm_spectatorfriction * pml.frametime;*/ - if (pm->ps.move_type == PM_SPECTATOR) - drop += speed * pm_flightfriction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - - newspeed /= speed; - - // vel *= newspeed - vel[0] = vel[0] * newspeed; - vel[1] = vel[1] * newspeed; - vel[2] = vel[2] * newspeed; -} - -float PM_CmdScale(playerMove::playercmd* const cmd) -{ - int max; - float total; - float scale; - - max = abs( cmd->forwardmove ); - if ( abs( cmd->rightmove ) > max ) - max = abs( cmd->rightmove ); - - if ( abs( cmd->upmove ) > max ) - max = abs( cmd->upmove ); - - if ( !max ) - return 0; - - total = sqrtf( (const float)(cmd->forwardmove * cmd->forwardmove - + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove) ); - scale = (float)pm->ps.speed * max / ( 127.0f * total ); - if(pm->ps.move_type == PM_NOCLIP) - scale *= 10; - - return scale; -} - -static void PM_Accelerate( Ogre::Vector3& wishdir, float wishspeed, float accel ) -{ -// int i; - float addspeed, accelspeed, currentspeed; - - - // currentspeed = pm->ps->velocity dot wishdir - //currentspeed = DotProduct (pm->ps->velocity, wishdir); - currentspeed = pm->ps.velocity.dotProduct(wishdir); - - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - - accelspeed = accel * pml.frametime * wishspeed; - - // Clamp accelspeed at addspeed - if (accelspeed > addspeed) - accelspeed = addspeed; - - // pm->ps->velocity += accelspeed * wishdir - //for (i=0 ; i<3 ; i++) - //pm->ps->velocity[i] += accelspeed * wishdir[i]; - pm->ps.velocity += (wishdir * accelspeed); - //pm->ps.velocity = wishdir * wishspeed; //New, for instant acceleration - -} - -static bool PM_CheckJump(void) -{ - //if ( pm->ps->pm_flags & PMF_RESPAWNED ) - //return qfalse; // don't allow jump until all buttons are up - - if ( pm->cmd.upmove < 10 ) - // not holding jump - return false; - - pm->cmd.upmove = 0; - - // must wait for jump to be released - /*if ( pm->ps->pm_flags & PMF_JUMP_HELD ) - { - // clear upmove so cmdscale doesn't lower running speed - pm->cmd.upmove = 0; - return false; - }*/ - - pml.groundPlane = false; // jumping away - pml.walking = false; - //pm->ps->pm_flags |= PMF_JUMP_HELD; - - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pm->ps.velocity.z = pm->ps.jump_velocity; - pm->ps.bSnap = false; - //PM_AddEvent( EV_JUMP ); - - /*if ( pm->cmd.forwardmove >= 0 ) - { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - }*/ - - return true; -} - -static void PM_WaterMove( playerMove* const pm ) -{ - //int i; - //vec3_t wishvel; - Ogre::Vector3 wishvel; - float wishspeed; - //vec3_t wishdir; - Ogre::Vector3 wishdir; - float scale; - float vel; - - pm->ps.bSnap = false; - - /*if ( PM_CheckWaterJump() ) - { - PM_WaterJumpMove(); - return; - }*/ -#if 0 - // jump = head for surface - if ( pm->cmd.upmove >= 10 ) { - if (pm->ps->velocity[2] > -300) { - if ( pm->watertype == CONTENTS_WATER ) { - pm->ps->velocity[2] = 100; - } else if (pm->watertype == CONTENTS_SLIME) { - pm->ps->velocity[2] = 80; - } else { - pm->ps->velocity[2] = 50; - } - } - } -#endif - PM_Friction (); - - if (pm->cmd.forwardmove || pm->cmd.rightmove) - { - //NEEDS TO BE REWRITTEN FOR OGRE TIME--------------------------------------------------- - /* - static const TimeTicks footstep_duration = GetTimeFreq(); // make each splash last 1.0s - static TimeTicks lastStepTime = 0; - const TimeTicks thisStepTime = GetTimeQPC(); - static bool lastWasLeft = false; - if (thisStepTime > lastStepTime) - { - if (pm->cmd.ducking) - lastStepTime = thisStepTime + footstep_duration * 2; // splashes while ducking are twice as slow - else - lastStepTime = thisStepTime + footstep_duration; - - lastWasLeft = !lastWasLeft; - */ - //-----------------jhooks1 - - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, lastWasLeft ? SNDG::r_swim : SNDG::l_swim); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - //Sound, ignore for now -- jhooks1 - //} - } - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) - { - /*wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = -60; // sink towards bottom - */ - wishvel.x = 0; - wishvel.z = -60; - wishvel.y = 0; - } - else - { - /*for (i=0 ; i<3 ; i++) - wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;*/ - wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; - - //wishvel[2] += scale * pm->cmd.upmove; - wishvel.z += pm->cmd.upmove * scale; - } - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - wishspeed = VectorNormalize(wishdir); - - if ( wishspeed > pm->ps.speed * pm_swimScale ) - wishspeed = pm->ps.speed * pm_swimScale; - - PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate); - - // make sure we can go up slopes easily under water - //if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) - if (pml.groundPlane && pm->ps.velocity.dotProduct(pml.groundTrace.planenormal) < 0.0f) - { - //vel = VectorLength(pm->ps->velocity); - vel = pm->ps.velocity.length(); - - // slide along the ground plane - //PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); - PM_ClipVelocity(pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP); - - VectorNormalize(pm->ps.velocity); - //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * vel; - } - - PM_SlideMove( false ); -} - -/* -=================== -PM_WalkMove - -=================== -*/ -static void PM_WalkMove( playerMove* const pmove ) -{ -// int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - playerMove::playercmd cmd; - float accelerate; - float vel; - //pm->ps.gravity = 4000; - - //std::cout << "Player is walking\n"; - - if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) - pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) - { - // begin swimming - PM_WaterMove(pmove); - return; - } - - - if ( PM_CheckJump () ) - { - - // jumped away - if ( pm->ps.waterlevel > 1 ) - PM_WaterMove(pmove); - else - PM_AirMove(); - //printf("Jumped away\n"); - return; - } - - // Footsteps time - if (pmove->cmd.forwardmove || pmove->cmd.rightmove) - { - bool step_underwater = false; - //if (pmove->traceObj) - //{ - - - //jhooks1 - Water handling, deal with later - - - - if (pmove->hasWater) - { - if (pmove->hasWater ) - { - const float waterHeight = pmove->waterHeight; - const float waterSoundStepHeight = waterHeight + pm->ps.halfExtents.y; - if (pmove->ps.origin.y < waterSoundStepHeight) - step_underwater = true; - } - } - //} - - /* - static const TimeTicks footstep_duration = GetTimeFreq() / 2; // make each footstep last 500ms - static TimeTicks lastStepTime = 0; - const TimeTicks thisStepTime = GetTimeQPC(); - static bool lastWasLeft = false; - if (thisStepTime > lastStepTime) - { - if (pmove->cmd.ducking) - lastStepTime = thisStepTime + footstep_duration * 2; // footsteps while ducking are twice as slow - else - lastStepTime = thisStepTime + footstep_duration; - - lastWasLeft = !lastWasLeft; - */ - - if (step_underwater) - { - /* - const namestruct ns(lastWasLeft ? "FootWaterRight" : "FootWaterLeft"); - const SOUN* const soun = SOUN::GetSound(ns); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - }*/ - } - else - { - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, lastWasLeft ? SNDG::r_foot : SNDG::l_foot); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - } - } - - - PM_Friction (); - - - //bprintf("vel: (%f, %f, %f)\n", pm->ps.velocity.x, pm->ps.velocity.y, pm->ps.velocity.z); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - //PM_SetMovementDir(); - - // project moves down to flat plane - //pml.forward[2] = 0; - pml.forward.z = 0; - - //pml.right[2] = 0; - pml.right.z = 0; - //std::cout << "Further down" << pm->ps.velocity << "\n"; - - - // project the forward and right directions onto the ground plane - PM_ClipVelocity (pml.forward, pml.groundTrace.planenormal, pml.forward, OVERCLIP ); - PM_ClipVelocity (pml.right, pml.groundTrace.planenormal, pml.right, OVERCLIP ); - //std::cout << "Clip velocity" << pm->ps.velocity << "\n"; - // - - VectorNormalize (pml.forward); - VectorNormalize (pml.right); - //pml.forward = pml.forward.normalise(); - //pml.right = pml.right.normalise(); - //std::cout << "forward2" << pml.forward << "\n"; - //std::cout << "right2" << pml.right << "\n"; - - - // wishvel = (pml.forward * fmove) + (pml.right * smove); - //for ( i = 0 ; i < 3 ; i++ ) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - - - //bprintf("f: (%f, %f, %f), s: (%f, %f, %f)\n", fmove, smove); - - - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - // wishdir = wishvel - //VectorCopy (wishvel, wishdir); - //wishvel = wishdir; - wishdir = wishvel; - - wishspeed = VectorNormalize(wishdir); - //std::cout << "Wishspeed: " << wishspeed << "\n"; - wishspeed *= scale; - //std::cout << "Wishspeed scaled:" << wishspeed << "\n"; - - // clamp the speed lower if ducking - if ( pm->cmd.ducking ) - if ( wishspeed > pm->ps.speed * pm_duckScale ) - wishspeed = pm->ps.speed * pm_duckScale; - - // clamp the speed lower if wading or walking on the bottom - if ( pm->ps.waterlevel ) - { - float waterScale; - - waterScale = pm->ps.waterlevel / 3.0f; - waterScale = 1.0f - ( 1.0f - pm_swimScale ) * waterScale; - if ( wishspeed > pm->ps.speed * waterScale ) - wishspeed = pm->ps.speed * waterScale; - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - //if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - //accelerate = pm_airaccelerate; - //else - accelerate = pm_accelerate; - - - PM_Accelerate (wishdir, wishspeed, accelerate); - //std::cout << "Velocityafter: " << pm->ps.velocity << "\n"; - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - //if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - //pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime; - //else - //{ - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - //} - - //vel = VectorLength(pm->ps->velocity); - vel = pm->ps.velocity.length(); - //std::cout << "The length" << vel << "\n"; - - // slide along the ground plane - PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, - pm->ps.velocity, OVERCLIP ); - //std::cout << "Velocity clipped" << pm->ps.velocity << "\n"; - - // don't decrease velocity when going up or down a slope - VectorNormalize(pm->ps.velocity); - //pm->ps.velocity = pm->ps.velocity.normalise(); - - //std::cout << "Final:" << pm->ps.velocity << "\n"; - //VectorScale(pm->ps->velocity, vel, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * vel; - - // don't do anything if standing still - //if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) - if (!pm->ps.velocity.x && !pm->ps.velocity.z) - return; - - PM_StepSlideMove( false ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - - -} - -void PM_UpdateViewAngles( playerMove::playerStruct* const ps, playerMove::playercmd* const cmd ) -{ - short temp; - int i; - - //while(1); - - //if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION) - //return; // no view changes at all - - //if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) - //return; // no view changes at all - - // circularly clamp the angles with deltas - //bprintf("View angles: %i, %i, %i\n", cmd->angles[0], cmd->angles[1], cmd->angles[2]); - for (i = 0 ; i < 3 ; i++) - { - temp = cmd->angles[i];// + ps->delta_angles[i]; - //if ( i == PITCH ) - { - // don't let the player look up or down more than 90 degrees - /*if ( temp > 16000 ) - { - ps->delta_angles[i] = 16000 - cmd->angles[i]; - temp = 16000; - } - else if ( temp < -16000 ) - { - ps->delta_angles[i] = -16000 - cmd->angles[i]; - temp = -16000; - }*/ - } - (&(ps->viewangles.x) )[i] = SHORT2ANGLE(temp); - //cmd->angles[i] += ps->delta_angles[i]; - } - //ps->delta_angles[0] = ps->delta_angles[1] = ps->delta_angles[2] = 0; - -} - -void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) -{ - float angle; - static float sr, sp, sy, cr, cp, cy; - // static to help MS compiler fp bugs - - //angle = angles[YAW] * (M_PI*2 / 360); - angle = angles.x * (M_PI * 2.0f / 360.0f); - sp = sinf(angle); - cp = cosf(angle); - - //angle = angles[PITCH] * (M_PI*2 / 360); - angle = angles.y * (-M_PI * 2.0f / 360.0f); - sy = sinf(angle); - cy = cosf(angle); - - //angle = angles[ROLL] * (M_PI*2 / 360); - angle = angles.z * (M_PI * 2.0f / 360.0f); - sr = sinf(angle); - cr = cosf(angle); - - if (forward) - { - forward->x = cp * cy; - forward->y = cp * sy; - forward->z = -sp; - } - if (right) - { - right->x = (-1 * sr * sp * cy + -1 * cr * -sy); - right->y = (-1 * sr * sp * sy + -1 * cr * cy); - right->z = 0; - } - if (up) - { - up->x =(cr * sp * cy + -sr * -sy); - up->y=(cr * sp * sy + -sr * cy); - up->z = cr * cp; - } - -} - -void PM_GroundTraceMissed() -{ - traceResults trace; - Ogre::Vector3 point; - //We should not have significant upwards velocity when in the air, unless we jumped. - //This code protects against flying into the air when moving at high speeds. - //Z velocity is set to 50, instead of 0, to help move up certain steps. - - //std::cout << "Ground trace missed\n"; - // we just transitioned into freefall - //if ( pm->debugLevel ) - //Com_Printf("%i:lift\n", c_pmove); - - // if they aren't in a jumping animation and the ground is a ways away, force into it - // if we didn't do the trace, the player would be backflipping down staircases - //VectorCopy( pm->ps->origin, point ); - point = pm->ps.origin; - //point[2] -= 64; - point.z -= 32; - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -64.0f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - //It hit the ground below - if ( trace.fraction < 1.0 && pm->ps.origin.z > trace.endpos.z) - { - pm->ps.origin = trace.endpos; - pml.walking = true; - pml.groundPlane = true; - pm->ps.groundEntityNum = trace.entityNum; - - } - else{ - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - pm->ps.bSnap = false; - } - - -} - -static bool PM_CorrectAllSolid(traceResults* const trace) -{ - int i, j, k; - Ogre::Vector3 point; - - //if ( pm->debugLevel ) - //Com_Printf("%i:allsolid\n", c_pmove); - //bprintf("allsolid\n"); - - // jitter around - for (i = -1; i <= 1; i++) - { - for (j = -1; j <= 1; j++) - { - for (k = -1; k <= 1; k++) - { - //VectorCopy(pm->ps->origin, point); - point = pm->ps.origin; - - /*point[0] += (float) i; - point[1] += (float) j; - point[2] += (float) k;*/ - point += Ogre::Vector3( (const float)i, (const float)j, (const float)k); - - //pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(trace, *(const D3DXVECTOR3* const)&point, *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0, pml.traceObj); - newtrace(trace, point, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - - if ( !trace->allsolid ) - { - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25;*/ - point = pm->ps.origin; - point.z -= 0.25f; - - //pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - pml.groundTrace = *trace; - return true; - } - } - } - } - - //pm->ps->groundEntityNum = ENTITYNUM_NONE; - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - - return false; -} - -static void PM_CrashLand( void ) -{ - float delta; - float dist ; - float vel, acc; - float t; - float a, b, c, den; - - // decide which landing animation to use - /*if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) - PM_ForceLegsAnim( LEGS_LANDB ); - else - PM_ForceLegsAnim( LEGS_LAND ); - - pm->ps->legsTimer = TIMER_LAND;*/ - - // calculate the exact velocity on landing - //dist = pm->ps->origin[2] - pml.previous_origin[2]; - - dist = pm->ps.origin.z - pml.previous_origin.z; - - //vel = pml.previous_velocity[2]; - vel = pml.previous_velocity.z; - - //acc = -pm->ps->gravity; - acc = -pm->ps.gravity; - - a = acc / 2; - b = vel; - c = -dist; - - den = b * b - 4 * a * c; - if ( den < 0 ) - return; - - t = (-b - sqrtf( den ) ) / ( 2 * a ); - - delta = vel + t * acc; - delta = delta * delta * 0.0001f; - - // ducking while falling doubles damage - /*if ( pm->ps->pm_flags & PMF_DUCKED ) - delta *= 2;*/ - if (pm->cmd.upmove < -20) - delta *= 2; - - // never take falling damage if completely underwater - if ( pm->ps.waterlevel == 3 ) - return; - - // reduce falling damage if there is standing water - if ( pm->ps.waterlevel == 2 ) - delta *= 0.25; - if ( pm->ps.waterlevel == 1 ) - delta *= 0.5; - - if ( delta < 1 ) - return; -/* - if (delta > 60) - printf("Far crashland: %f\n", delta); - else if (delta > 40) - printf("Medium crashland: %f\n", delta); - else if (delta > 4) - printf("Short crashland: %f\n", delta); -*/ - if (delta > 60) - { - /* - static const namestruct healthDamage("Health Damage"); - const SOUN* const soun = SOUN::GetSound(healthDamage); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - }*/ - } - - if (delta > 3) // We need at least a short crashland to proc the sound effects: - { - bool splashSound = false; - - if (pm->hasWater) - { - - const float waterHeight = pm->waterHeight; - const float waterHeightSplash = waterHeight + pm->ps.halfExtents.y; - if (pm->ps.origin.z < waterHeightSplash) - { - splashSound = true; - } - - } - - - if (splashSound) - { - //Change this later----------------------------------- - /* - const namestruct ns("DefaultLandWater"); - const SOUN* const soun = SOUN::GetSound(ns); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundDatga->GetVolumeFloat() ); - }*/ - } - else - { - //Change this later--------------------------------- - /* - namestruct defaultCreature; - const SNDG* const sndg = SNDG::GetFromMap(defaultCreature, SNDG::land); - if (sndg) - { - const namestruct& SOUNID = sndg->soundID; - const SOUN* const soun = SOUN::GetSound(SOUNID); - if (soun) - { - PlaySound2D(soun->soundFilename, soun->soundData->GetVolumeFloat() ); - } - }*/ - } - } - - // create a local entity event to play the sound - - // SURF_NODAMAGE is used for bounce pads where you don't ever - // want to take damage or play a crunch sound - //if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) - { - /*if ( delta > 60 ) - PM_AddEvent( EV_FALL_FAR ); - else if ( delta > 40 ) - { - // this is a pain grunt, so don't play it if dead - if ( pm->ps->stats[STAT_HEALTH] > 0 ) - PM_AddEvent( EV_FALL_MEDIUM ); - } - else if ( delta > 7 ) - PM_AddEvent( EV_FALL_SHORT ); - else - PM_AddEvent( PM_FootstepForSurface() );*/ - } - - // start footstep cycle over - //pm->ps->bobCycle = 0; -} - -static void PM_GroundTrace( void ) -{ - Ogre::Vector3 point; - traceResults trace; - - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] - 0.25;*/ - point = pm->ps.origin; - point.z -= 0.25f; - - //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); - //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); - pml.groundTrace = trace; - - // do something corrective if the trace starts in a solid... - if ( trace.allsolid ) { - //std::cout << "ALL SOLID\n"; - if ( !PM_CorrectAllSolid(&trace) ){ - //std::cout << "Returning after correct all solid\n"; - return; - } - } - // if the trace didn't hit anything, we are in free fall - if ( trace.fraction == 1.0) - { - if(pm->ps.velocity.z > 50.0f && pm->ps.bSnap && pm->ps.speed > 1000.0f) - pm->ps.velocity.z = 50.0f; - if(pm->ps.snappingImplemented){ - if(pm->ps.bSnap && pm->ps.counter <= 0) - PM_GroundTraceMissed(); - } - - - - return; - } - else - { - //It hit something, so we are on the ground - pm->ps.bSnap = true; - - } - // check if getting thrown off the ground - //if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) - if (pm->ps.velocity.z > 0 && pm->ps.velocity.dotProduct(trace.planenormal) > 10.0f ) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:kickoff\n", c_pmove); - - // go into jump animation - /*if ( pm->cmd.forwardmove >= 0 ) - { - PM_ForceLegsAnim( LEGS_JUMP ); - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - PM_ForceLegsAnim( LEGS_JUMPB ); - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - }*/ - if(!pm->ps.bSnap){ - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = false; - pml.walking = false; - } - else - { - pml.groundPlane = true; - pml.walking = true; - } - return; - } - - - - - // slopes that are too steep will not be considered onground - //if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) - //std::cout << "MinWalkNormal" << trace.planenormal.z; - if (trace.planenormal.z < MIN_WALK_NORMAL) - { - //if ( pm->debugLevel ) - //Com_Printf("%i:steep\n", c_pmove); - - // FIXME: if they can't slide down the slope, let them - // walk (sharp crevices) - pm->ps.groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = true; - pml.walking = false; - return; - } - - pml.groundPlane = true; - pml.walking = true; - - // hitting solid ground will end a waterjump - /*if (pm->ps.pm_flags & PMF_TIME_WATERJUMP) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - }*/ - - if ( pm->ps.groundEntityNum == ENTITYNUM_NONE ) - { - // just hit the ground - /*if ( pm->debugLevel ) - Com_Printf("%i:Land\n", c_pmove);*/ - //bprintf("Land\n"); - - PM_CrashLand(); - - // don't do landing time if we were just going down a slope - //if ( pml.previous_velocity[2] < -200 ) - if (pml.previous_velocity.z < -200) - { - // don't allow another jump for a little while - //pm->ps->pm_flags |= PMF_TIME_LAND; - pm->ps.pm_time = 250; - } - } - - pm->ps.groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - //PM_AddTouchEnt( trace.entityNum ); -} - -void PM_AirMove() -{ - //int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - playerMove::playercmd cmd; - //pm->ps.gravity = 800; - PM_Friction(); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - // set the movementDir so clients can rotate the legs for strafing - //PM_SetMovementDir(); - - // project moves down to flat plane - //pml.forward[2] = 0; - pml.forward.z = 0; //Z or Y? - //pml.right[2] = 0; - pml.right.z = 0; - //VectorNormalize (pml.forward); - VectorNormalize(pml.forward); - VectorNormalize(pml.right); - //VectorNormalize (pml.right); - - //for ( i = 0 ; i < 2 ; i++ ) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - wishvel = pml.forward * fmove + pml.right * smove; - - //wishvel[2] = 0; - wishvel.z = 0; - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - //wishspeed = VectorNormalize(wishdir); - wishspeed = VectorNormalize(wishdir); - - wishspeed *= scale; - - // not on ground, so little effect on velocity - PM_Accelerate (wishdir, wishspeed, pm_airaccelerate); - - // we may have a ground plane that is very steep, even - // though we don't have a groundentity - // slide along the steep plane - if ( pml.groundPlane ) - PM_ClipVelocity (pm->ps.velocity, pml.groundTrace.planenormal, pm->ps.velocity, OVERCLIP ); - -/*#if 0 - //ZOID: If we are on the grapple, try stair-stepping - //this allows a player to use the grapple to pull himself - //over a ledge - if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - PM_StepSlideMove ( qtrue ); - else - PM_SlideMove ( qtrue ); -#endif*/ - //std::cout << "Moving in the air" << pm->ps.velocity << "\n"; - - /*bprintf("%i ", */PM_StepSlideMove ( true )/* )*/; - - -} - -static void PM_NoclipMove( void ) -{ - float speed, drop, friction, control, newspeed; -// int i; - Ogre::Vector3 wishvel; - float fmove, smove; - Ogre::Vector3 wishdir; - float wishspeed; - float scale; - - //pm->ps->viewheight = DEFAULT_VIEWHEIGHT; - - // friction - - //speed = VectorLength (pm->ps->velocity); - speed = pm->ps.velocity.length(); - if (speed < 1) - //VectorCopy (vec3_origin, pm->ps->velocity); - pm->ps.velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - else - { - drop = 0; - - friction = pm_friction * 1.5f; // extra friction - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - //VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity); - pm->ps.velocity = pm->ps.velocity * newspeed; - } - - // accelerate - scale = PM_CmdScale( &pm->cmd ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - //for (i=0 ; i<3 ; i++) - //wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove; - - wishvel = pml.forward * fmove + pml.right * smove; - //wishvel[2] += pm->cmd.upmove; - wishvel.z += pm->cmd.upmove; - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - wishspeed = VectorNormalize(wishdir); - wishspeed *= scale; - - - PM_Accelerate( wishdir, wishspeed, pm_accelerate ); - - // move - //VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin); - pm->ps.origin = pm->ps.origin + pm->ps.velocity * pml.frametime; -} - -static void PM_DropTimers( void ) -{ - // drop misc timing counter - if ( pm->ps.pm_time ) - { - if ( pml.msec >= pm->ps.pm_time ) - { - //pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps.pm_time = 0; - } - else - pm->ps.pm_time -= pml.msec; - } - - //bprintf("Time: %i\n", pm->ps.pm_time); - - // drop animation counter - /*if ( pm->ps->legsTimer > 0 ) - { - pm->ps->legsTimer -= pml.msec; - if ( pm->ps->legsTimer < 0 ) - pm->ps->legsTimer = 0; - } - - if ( pm->ps->torsoTimer > 0 ) - { - pm->ps->torsoTimer -= pml.msec; - if ( pm->ps->torsoTimer < 0 ) - pm->ps->torsoTimer = 0; - }*/ -} - -static void PM_FlyMove( void ) -{ - //int i; - Ogre::Vector3 wishvel; - float wishspeed; - Ogre::Vector3 wishdir; - float scale; - - // normal slowdown - PM_Friction (); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if ( !scale ) - { - /*wishvel[0] = 0; - wishvel[1] = 0; - wishvel[2] = 0;*/ - wishvel = Ogre::Vector3(0,0,0); - } - else - { - //for (i=0 ; i<3 ; i++) - //wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; - wishvel = pml.forward * scale * pm->cmd.forwardmove + pml.right * scale * pm->cmd.rightmove; - - //wishvel[2] += scale * pm->cmd.upmove; - wishvel.z += /*6.35f * */pm->cmd.upmove * scale; - } - - //VectorCopy (wishvel, wishdir); - wishdir = wishvel; - - //wishspeed = VectorNormalize(wishdir); - wishspeed = VectorNormalize(wishdir); - - PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate); - - PM_StepSlideMove( false ); -} - - -void PM_SetWaterLevel( playerMove* const pm ) -{ - Ogre::Vector3 point; - //int cont; - int sample1; - int sample2; - - // - // get waterlevel, accounting for ducking - // - - pm->ps.waterlevel = WL_DRYLAND; - pm->ps.watertype = 0; - - /*point[0] = pm->ps->origin[0]; - point[1] = pm->ps->origin[1]; - point[2] = pm->ps->origin[2] + MINS_Z + 1; */ - point.x = pm->ps.origin.x; - point.y = pm->ps.origin.y; - point.z = pm->ps.origin.z + MINS_Z + 1; - - //cont = pm->pointcontents( point, pm->ps->clientNum ); - bool checkWater = (pml.hasWater && pml.waterHeight > point.z); - //if ( cont & MASK_WATER ) - if ( checkWater) - { - sample2 = /*pm->ps.viewheight*/DEFAULT_VIEWHEIGHT - MINS_Z; - sample1 = sample2 / 2; - - pm->ps.watertype = CONTENTS_WATER;//cont; - pm->ps.waterlevel = WL_ANKLE; - //point[2] = pm->ps->origin[2] + MINS_Z + sample1; - point.z = pm->ps.origin.z + MINS_Z + sample1; - checkWater = (pml.hasWater && pml.waterHeight > point.z); - //cont = pm->pointcontents (point, pm->ps->clientNum ); - //if ( cont & MASK_WATER ) - if (checkWater) - { - pm->ps.waterlevel = WL_WAIST; - //point[2] = pm->ps->origin[2] + MINS_Z + sample2; - point.z = pm->ps.origin.z + MINS_Z + sample2; - //cont = pm->pointcontents (point, pm->ps->clientNum ); - //if ( cont & MASK_WATER ) - checkWater = (pml.hasWater && pml.waterHeight > point.z); - if (checkWater ) - pm->ps.waterlevel = WL_UNDERWATER; - } - } -} - -void PmoveSingle (playerMove* const pmove) -{ - pmove->ps.counter--; - //pm = pmove; - - // Aedra doesn't support Q3-style VM traps D: //while(1); - - // this counter lets us debug movement problems with a journal - // by setting a conditional breakpoint fot the previous frame - //c_pmove++; - - // clear results - //pm->numtouch = 0; - pm->ps.watertype = 0; - pm->ps.waterlevel = WL_DRYLAND; - - //if ( pm->ps->stats[STAT_HEALTH] <= 0 ) - //pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies - - - // make sure walking button is clear if they are running, to avoid - // proxy no-footsteps cheats - //if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) - //pm->cmd.buttons &= ~BUTTON_WALKING; - - - // set the talk balloon flag - //if ( pm->cmd.buttons & BUTTON_TALK ) - //pm->ps->eFlags |= EF_TALK; - //else - //pm->ps->eFlags &= ~EF_TALK; - - // set the firing flag for continuous beam weapons - /*if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION - && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) - pm->ps->eFlags |= EF_FIRING; - else - pm->ps->eFlags &= ~EF_FIRING;*/ - - // clear the respawned flag if attack and use are cleared - /*if ( pm->ps->stats[STAT_HEALTH] > 0 && - !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) - pm->ps->pm_flags &= ~PMF_RESPAWNED;*/ - - // if talk button is down, dissallow all other input - // this is to prevent any possible intercept proxy from - // adding fake talk balloons - /*if ( pmove->cmd.buttons & BUTTON_TALK ) - { - // keep the talk button set tho for when the cmd.serverTime > 66 msec - // and the same cmd is used multiple times in Pmove - pmove->cmd.buttons = BUTTON_TALK; - pmove->cmd.forwardmove = 0; - pmove->cmd.rightmove = 0; - pmove->cmd.upmove = 0; - }*/ - - // clear all pmove local vars - memset (&pml, 0, sizeof(pml) ); - - // Aedra-specific code: - //pml.scene = global_lastscene; - - - // End Aedra-specific code - pml.hasWater = pmove->hasWater; - pml.isInterior = pmove->isInterior; - pml.waterHeight = pmove->waterHeight; - - // determine the time - pml.msec = pmove->cmd.serverTime - pm->ps.commandTime; - if ( pml.msec < 1 ) - pml.msec = 1; - else if ( pml.msec > 200 ) - pml.msec = 200; - - //pm->ps->commandTime = pmove->cmd.serverTime; - - // Commented out as a hack - pm->ps.commandTime = pmove->cmd.serverTime; - - // Handle state change procs: - if (pm->cmd.activating != pm->cmd.lastActivatingState) - { - if (!pm->cmd.lastActivatingState && pm->cmd.activating) - pm->cmd.procActivating = playerMove::playercmd::KEYDOWN; - else - pm->cmd.procActivating = playerMove::playercmd::KEYUP; - } - else - { - pm->cmd.procActivating = playerMove::playercmd::NO_CHANGE; - } - pm->cmd.lastActivatingState = pm->cmd.activating; - - if (pm->cmd.dropping != pm->cmd.lastDroppingState) - { - if (!pm->cmd.lastDroppingState && pm->cmd.dropping) - pm->cmd.procDropping = playerMove::playercmd::KEYDOWN; - else - pm->cmd.procDropping = playerMove::playercmd::KEYUP; - } - else - { - pm->cmd.procDropping = playerMove::playercmd::NO_CHANGE; - } - pm->cmd.lastDroppingState = pm->cmd.dropping; - - // save old org in case we get stuck - //VectorCopy (pm->ps->origin, pml.previous_origin); - pml.previous_origin = pm->ps.origin; - - // Copy over the lastframe origin - pmove->ps.lastframe_origin = pmove->ps.origin; - - //pmove->ps.lastframe_origin = pmove->ps.origin; - - // save old velocity for crashlanding - //VectorCopy (pm->ps->velocity, pml.previous_velocity); - pml.previous_velocity = pm->ps.velocity; - - pml.frametime = pml.msec * 0.001f; - - // update the viewangles - //PM_UpdateViewAngles( &(pm->ps), &(pm->cmd) ); - - AngleVectors (pm->ps.viewangles, &(pml.forward), &(pml.right), &(pml.up) ); - - //if ( pm->cmd.upmove < 10 ) - // not holding jump - //pm->ps->pm_flags &= ~PMF_JUMP_HELD; - - // decide if backpedaling animations should be used - /*if ( pm->cmd.forwardmove < 0 ) - pm->ps->pm_flags |= PMF_BACKWARDS_RUN; - else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) - pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;*/ - - /*if ( pm->ps->pm_type >= PM_DEAD ) - { - pm->cmd.forwardmove = 0; - pm->cmd.rightmove = 0; - pm->cmd.upmove = 0; - }*/ - - if ( pm->ps.move_type == PM_SPECTATOR ) - { - - //PM_CheckDuck (); - PM_FlyMove (); - PM_DropTimers (); - return; - } - - if ( pm->ps.move_type == PM_NOCLIP ) - { - - PM_NoclipMove (); - PM_DropTimers (); - return; - } - - if (pm->ps.move_type == PM_FREEZE){ - - return; // no movement at all - - } - - if ( pm->ps.move_type == PM_INTERMISSION || pm->ps.move_type == PM_SPINTERMISSION){ - return; // no movement at all - } - - // set watertype, and waterlevel - PM_SetWaterLevel(pmove); - pml.previous_waterlevel = pmove->ps.waterlevel; - - // set mins, maxs, and viewheight - //PM_CheckDuck (); - - // set groundentity - PM_GroundTrace(); - - /*if ( pm->ps->pm_type == PM_DEAD ) - PM_DeadMove (); - - PM_DropTimers();*/ - - PM_DropTimers(); - -/*#ifdef MISSIONPACK - if ( pm->ps->powerups[PW_INVULNERABILITY] ) { - PM_InvulnerabilityMove(); - } else -#endif*/ - /*if ( pm->ps->powerups[PW_FLIGHT] ) - // flight powerup doesn't allow jump and has different friction - PM_FlyMove(); - else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) - { - PM_GrappleMove(); - // We can wiggle a bit - PM_AirMove(); - } - else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) - PM_WaterJumpMove();*/ - if ( pmove->ps.waterlevel > 1 ) - // swimming - PM_WaterMove(pmove); - else if ( pml.walking ) - { - - // walking on ground - PM_WalkMove(pmove); - //bprintf("WalkMove\n"); - } - else - { - // airborne - //std::cout << "AIRMOVE\n"; - PM_AirMove(); - //bprintf("AirMove\n"); - } - - //PM_Animate(); - - // set groundentity, watertype, and waterlevel - PM_GroundTrace(); - PM_SetWaterLevel(pmove); - - // weapons - /*PM_Weapon(); - - // torso animation - PM_TorsoAnimation(); - - // footstep events / legs animations - PM_Footsteps(); - - // entering / leaving water splashes - PM_WaterEvents(); - - // snap some parts of playerstate to save network bandwidth - trap_SnapVector( pm->ps->velocity );*/ -} - -void Ext_UpdateViewAngles(playerMove* const pm) -{ - playerMove::playerStruct* const ps = &(pm->ps); - playerMove::playercmd* const cmd = &(pm->cmd); - PM_UpdateViewAngles(ps, cmd); -} - -void Pmove (playerMove* const pmove) -{ - // warning: unused variable ‘fmove’ - //int fmove = pmove->cmd.forwardmove; - - pm = pmove; - - int finalTime; - - finalTime = pmove->cmd.serverTime; - - pmove->ps.commandTime = 40; - - if ( finalTime < pmove->ps.commandTime ) - return; // should not happen - - if ( finalTime > pmove->ps.commandTime + 1000 ) - pmove->ps.commandTime = finalTime - 1000; - - pmove->ps.pmove_framecount = (pmove->ps.pmove_framecount + 1) & ( (1 << PS_PMOVEFRAMECOUNTBITS) - 1); - - // chop the move up if it is too long, to prevent framerate - // dependent behavior - while ( pmove->ps.commandTime != finalTime ) - { - int msec; - - msec = finalTime - pmove->ps.commandTime; - - if ( pmove->pmove_fixed ) - { - if ( msec > pmove->pmove_msec ) - msec = pmove->pmove_msec; - } - else - { - if ( msec > 66 ) - msec = 66; - } - - pmove->cmd.serverTime = pmove->ps.commandTime + msec; - - if (pmove->isInterior) - { - PmoveSingle( pmove ); - } - else - { - PmoveSingle( pmove ); - /* - std::map::const_iterator it = ExtCellLookup.find(PositionToCell(pmove->ps.origin) ); - if (it != ExtCellLookup.end() ) - { - pmove->traceObj->incellptr = it->second; - }*/ - } - - //if ( pmove->ps->pm_flags & PMF_JUMP_HELD ) - //pmove->cmd.upmove = 20; - } - - //pmove->ps.last_compute_time = GetTimeQPC(); - //pmove->ps.lerp_multiplier = (pmove->ps.origin - pmove->ps.lastframe_origin);// * (1.000 / 31.0); - - //PM_CheckStuck(); - -} - - diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h deleted file mode 100644 index 29a050471..000000000 --- a/libs/openengine/bullet/pmove.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef OENGINE_BULLET_PMOVE_H -#define OENGINE_BULLET_PMOVE_H -/* -This source file is a *modified* version of various header files from the Quake 3 Arena source code, -which was released under the GNU GPL (v2) in 2005. -Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. -*/ - -#include -#include - -#include - -//#include "GameMath.h" -//#include "GameTime.h" - -// Forwards-declare it! - -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - -/*#ifndef COMPILING_PMOVE -#include "Scene.h" -extern SceneInstance* global_lastscene; -#endif*/ - -static const Ogre::Vector3 halfExtentsDefault(14.64f * 2, 14.24f * 2, 33.25f * 2); - -#define MAX_CLIP_PLANES 5 -#define OVERCLIP 1.001f -//#define STEPSIZE 18 // 18 is way too much -#define STEPSIZE (9) -#ifndef M_PI - #define M_PI 3.14159265358979323846f -#endif -#define YAW 0 -#define PITCH /*1*/2 -#define ROLL /*2*/1 -#define SHORT2ANGLE(x) ( (x) * (360.0f / 65536.0f) ) -#define ANGLE2SHORT(x) ( (const short)( (x) / (360.0f / 65536.0f) ) ) -#define GENTITYNUM_BITS 10 // don't need to send any more -#define MAX_GENTITIES (1 << GENTITYNUM_BITS) -#define ENTITYNUM_NONE (MAX_GENTITIES - 1) -#define ENTITYNUM_WORLD (MAX_GENTITIES - 2) -#define MIN_WALK_NORMAL .7f // can't walk on very steep slopes -#define PS_PMOVEFRAMECOUNTBITS 6 -#define MINS_Z -24 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 -#define DEAD_VIEWHEIGHT (-16) -#define CONTENTS_SOLID 1 // an eye is never valid in a solid -#define CONTENTS_LAVA 8 -#define CONTENTS_SLIME 16 -#define CONTENTS_WATER 32 -#define CONTENTS_FOG 64 -static const float pm_accelerate = 10.0f; -static const float pm_stopspeed = 100.0f; -static const float pm_friction = 12.0f; -static const float pm_flightfriction = 3.0f; -static const float pm_waterfriction = 1.0f; -static const float pm_airaccelerate = 1.0f; -static const float pm_swimScale = 0.50f; -static const float pm_duckScale = 0.25f; -static const float pm_flyaccelerate = 8.0f; -static const float pm_wateraccelerate = 4.0f; - -enum pmtype_t -{ - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar -}; - -enum waterlevel_t -{ - WL_DRYLAND = 0, - WL_ANKLE, - WL_WAIST, - WL_UNDERWATER -}; - - -//#include "bprintf.h" - -struct playerMove -{ - struct playerStruct - { - playerStruct() : gravity(800.0f), speed(480.0f), jump_velocity(270), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0), snappingImplemented(true), bSnap(false), counter(-1), halfExtents(halfExtentsDefault) - { - origin = Ogre::Vector3(0.0f, 0.0f, 0.0f); - velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - viewangles = Ogre::Vector3(0.0f, 0.0f, 0.0f); - - delta_angles[0] = delta_angles[1] = delta_angles[2] = 0; - - lastframe_origin.x = lastframe_origin.y = lastframe_origin.z = 0; - lerp_multiplier.x = lerp_multiplier.y = lerp_multiplier.z = 0; - } - - inline void SpeedUp(void) - { - //printf("speed up to: %f\n", speed); - speed *= 1.25f; - } - - inline void SpeedDown(void) - { - //printf("speed down to %f\n", speed); - speed /= 1.25f; - } - - Ogre::Vector3 velocity; - Ogre::Vector3 origin; - Ogre::Vector3 halfExtents; - bool bSnap; - bool snappingImplemented; - int counter; - float gravity; // default = 800 - float speed; // default = 320 - float jump_velocity; //default = 270 - - int commandTime; // the time at which this command was issued (in milliseconds) - - int pm_time; - - Ogre::Vector3 viewangles; - - int groundEntityNum; - - int pmove_framecount; - - int watertype; - waterlevel_t waterlevel; - - signed short delta_angles[3]; - - pmtype_t move_type; - - float last_compute_time; - Ogre::Vector3 lastframe_origin; - Ogre::Vector3 lerp_multiplier; - } ps; - - struct playercmd - { - enum CMDstateChange - { - NO_CHANGE, - KEYDOWN, - KEYUP - }; - - playercmd() : forwardmove(0), rightmove(0), upmove(0), serverTime(50), ducking(false), - activating(false), lastActivatingState(false), procActivating(NO_CHANGE), - dropping(false), lastDroppingState(false), procDropping(NO_CHANGE) - { - angles[0] = angles[1] = angles[2] = 0; - } - - int serverTime; - - short angles[3]; - - signed char forwardmove; - signed char rightmove; - signed char upmove; - - bool ducking; - bool activating; // if the user is holding down the activate button - bool dropping; // if the user is dropping an item - - bool lastActivatingState; - bool lastDroppingState; - - CMDstateChange procActivating; - CMDstateChange procDropping; - } cmd; - - playerMove() : msec(50), pmove_fixed(false), pmove_msec(50), waterHeight(0), isInterior(true), hasWater(false) - { - } - - int msec; - int pmove_msec; - bool pmove_fixed; - int waterHeight; - bool hasWater; - bool isInterior; - OEngine::Physic::PhysicEngine* mEngine; -}; - -void Pmove (playerMove* const pmove); -void Ext_UpdateViewAngles(playerMove* const pm); -void AngleVectors( const Ogre::Vector3& angles, Ogre::Vector3* const forward, Ogre::Vector3* const right, Ogre::Vector3* const up) ; -#endif diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 138411e11..618f6ee65 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -7,7 +7,6 @@ #include #include "physic.hpp" -#include "pmove.h" enum traceWorldType @@ -105,7 +104,6 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr { results->endpos = end; results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); - results->entityNum = ENTITYNUM_NONE; results->fraction = 1.0f; } else @@ -113,6 +111,5 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr results->fraction = out.fraction; results->planenormal = out.hitNormal; results->endpos = (end-start)*results->fraction + start; - results->entityNum = ENTITYNUM_WORLD; } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 94708d403..7b17da178 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -20,10 +20,6 @@ struct traceResults float fraction; - int surfaceFlags; - int contents; - int entityNum; - bool allsolid; bool startsolid; }; From 35b68a3c400ed79762338835ef77b48b5bde95b0 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 19 Feb 2013 15:58:01 +0100 Subject: [PATCH 677/916] Fixed accidental profile deletion and added sorting by date --- apps/launcher/CMakeLists.txt | 6 ++ apps/launcher/datafilespage.cpp | 71 +++++++++++-------- apps/launcher/datafilespage.hpp | 4 +- apps/launcher/maindialog.cpp | 2 - apps/launcher/model/pluginsproxymodel.cpp | 17 +++++ apps/launcher/model/pluginsproxymodel.hpp | 18 +++++ apps/launcher/settings/gamesettings.cpp | 55 ++++++++------ apps/launcher/settings/launchersettings.cpp | 17 ++--- apps/launcher/settings/settingsbase.hpp | 2 - .../fileorderlist/model/datafilesmodel.cpp | 21 +++++- 10 files changed, 146 insertions(+), 67 deletions(-) create mode 100644 apps/launcher/model/pluginsproxymodel.cpp create mode 100644 apps/launcher/model/pluginsproxymodel.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 2c17e06b4..59cccad5f 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -5,6 +5,8 @@ set(LAUNCHER maindialog.cpp playpage.cpp + model/pluginsproxymodel.cpp + settings/gamesettings.cpp settings/graphicssettings.cpp settings/launchersettings.cpp @@ -22,6 +24,8 @@ set(LAUNCHER_HEADER maindialog.hpp playpage.hpp + model/pluginsproxymodel.hpp + settings/gamesettings.hpp settings/graphicssettings.hpp settings/launchersettings.hpp @@ -39,6 +43,8 @@ set(LAUNCHER_HEADER_MOC maindialog.hpp playpage.hpp + model/pluginsproxymodel.hpp + utils/comboboxlineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index e0ebefa58..4ecb67e4e 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -9,6 +9,8 @@ #include #include +#include "model/pluginsproxymodel.hpp" + #include "settings/gamesettings.hpp" #include "settings/launchersettings.hpp" @@ -63,7 +65,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); mMastersProxyModel->setSourceModel(mDataFilesModel); - mPluginsProxyModel = new QSortFilterProxyModel(); + mPluginsProxyModel = new PluginsProxyModel(); mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); mPluginsProxyModel->setSourceModel(mDataFilesModel); @@ -97,6 +99,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersTable = new QTableView(this); mMastersTable->setModel(mMastersProxyModel); mMastersTable->setObjectName("MastersTable"); + mMastersTable->setSortingEnabled(false); mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection); mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -108,19 +111,12 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersTable->verticalHeader()->setDefaultSectionSize(height); mMastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); mMastersTable->verticalHeader()->hide(); - mMastersTable->setColumnHidden(1, true); - mMastersTable->setColumnHidden(2, true); - mMastersTable->setColumnHidden(3, true); - mMastersTable->setColumnHidden(4, true); - mMastersTable->setColumnHidden(5, true); - mMastersTable->setColumnHidden(6, true); - mMastersTable->setColumnHidden(7, true); - mMastersTable->setColumnHidden(8, true); mPluginsTable = new QTableView(this); mPluginsTable->setModel(mFilterProxyModel); mPluginsTable->setObjectName("PluginsTable"); mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); + mPluginsTable->setSortingEnabled(false); mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); mPluginsTable->setSelectionMode(QAbstractItemView::SingleSelection); mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -131,14 +127,6 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mPluginsTable->verticalHeader()->setDefaultSectionSize(height); mPluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mPluginsTable->setColumnHidden(1, true); - mPluginsTable->setColumnHidden(2, true); - mPluginsTable->setColumnHidden(3, true); - mPluginsTable->setColumnHidden(4, true); - mPluginsTable->setColumnHidden(5, true); - mPluginsTable->setColumnHidden(6, true); - mPluginsTable->setColumnHidden(7, true); - mPluginsTable->setColumnHidden(8, true); // Add both tables to a splitter mSplitter = new QSplitter(this); @@ -185,12 +173,11 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + + connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); - connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); - connect(mSplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); createActions(); @@ -250,9 +237,13 @@ void DataFilesPage::setupDataFiles() mDataFilesModel->addFiles(dataLocal); } + // Sort by date accessed for now + mDataFilesModel->sort(3); + QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + mProfilesComboBox->setCurrentIndex(-1); mProfilesComboBox->addItems(profiles); // Add the current profile if empty @@ -262,12 +253,18 @@ void DataFilesPage::setupDataFiles() if (mProfilesComboBox->findText(QString("Default")) == -1) mProfilesComboBox->addItem(QString("Default")); - if (profile.isEmpty()) { + + if (profile.isEmpty() || profile == QLatin1String("Default")) { mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(QString("Default"))); } else { + mProfilesComboBox->setEditEnabled(true); mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); } + // We do this here to prevent deletion of profiles when initializing the combobox + connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); + connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); + loadSettings(); } @@ -301,10 +298,8 @@ void DataFilesPage::saveSettings() { QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); - if (profile.isEmpty()) { - profile = mProfilesComboBox->currentText(); - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), profile); - } + if (profile.isEmpty()) + return; mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); @@ -360,6 +355,28 @@ void DataFilesPage::updateSplitter() mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1))); } +void DataFilesPage::updateViews() +{ + // Ensure the columns are hidden because sort() re-enables them + mMastersTable->setColumnHidden(1, true); + mMastersTable->setColumnHidden(2, true); + mMastersTable->setColumnHidden(3, true); + mMastersTable->setColumnHidden(4, true); + mMastersTable->setColumnHidden(5, true); + mMastersTable->setColumnHidden(6, true); + mMastersTable->setColumnHidden(7, true); + mMastersTable->setColumnHidden(8, true); + + mPluginsTable->setColumnHidden(1, true); + mPluginsTable->setColumnHidden(2, true); + mPluginsTable->setColumnHidden(3, true); + mPluginsTable->setColumnHidden(4, true); + mPluginsTable->setColumnHidden(5, true); + mPluginsTable->setColumnHidden(6, true); + mPluginsTable->setColumnHidden(7, true); + mPluginsTable->setColumnHidden(8, true); +} + void DataFilesPage::deleteProfile() { QString profile = mProfilesComboBox->currentText(); @@ -441,7 +458,7 @@ void DataFilesPage::uncheck() void DataFilesPage::refresh() { - mDataFilesModel->sort(0); +// mDataFilesModel->sort(0); // Refresh the plugins table mPluginsTable->scrollToTop(); @@ -512,7 +529,6 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre saveSettings(); mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); - mDataFilesModel->uncheckAll(); loadSettings(); } @@ -532,7 +548,6 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre // Remove the profile from the combobox mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); - mDataFilesModel->uncheckAll(); loadSettings(); } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index e6b4194bd..2561aa3d1 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -18,6 +18,7 @@ class TextInputDialog; class ProfilesComboBox; class GameSettings; class LauncherSettings; +class PluginsProxyModel; namespace Files { struct ConfigurationManager; } @@ -43,6 +44,7 @@ public slots: void profileRenamed(const QString &previous, const QString ¤t); void updateOkButton(const QString &text); void updateSplitter(); + void updateViews(); // Action slots void newProfile(); @@ -58,7 +60,7 @@ public slots: private: DataFilesModel *mDataFilesModel; - QSortFilterProxyModel *mPluginsProxyModel; + PluginsProxyModel *mPluginsProxyModel; QSortFilterProxyModel *mMastersProxyModel; QSortFilterProxyModel *mFilterProxyModel; diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 7b453671c..15f2690da 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -206,8 +206,6 @@ void MainDialog::saveSettings() mLauncherSettings.setValue(QString("General/MainWindow/posx"), posX); mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY); - - qDebug() << "size: " << width << height; } void MainDialog::writeSettings() diff --git a/apps/launcher/model/pluginsproxymodel.cpp b/apps/launcher/model/pluginsproxymodel.cpp new file mode 100644 index 000000000..6be152b55 --- /dev/null +++ b/apps/launcher/model/pluginsproxymodel.cpp @@ -0,0 +1,17 @@ +#include "pluginsproxymodel.hpp" + +PluginsProxyModel::PluginsProxyModel(QObject *parent) : + QSortFilterProxyModel(parent) +{ +} + +PluginsProxyModel::~PluginsProxyModel() +{ +} + +QVariant PluginsProxyModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation != Qt::Vertical || role != Qt::DisplayRole) + return QSortFilterProxyModel::headerData(section, orientation, role); + return section + 1; +} diff --git a/apps/launcher/model/pluginsproxymodel.hpp b/apps/launcher/model/pluginsproxymodel.hpp new file mode 100644 index 000000000..8fde73236 --- /dev/null +++ b/apps/launcher/model/pluginsproxymodel.hpp @@ -0,0 +1,18 @@ +#ifndef PLUGINSPROXYMODEL_HPP +#define PLUGINSPROXYMODEL_HPP + +#include + +class QVariant; + +class PluginsProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + explicit PluginsProxyModel(QObject *parent = 0); + ~PluginsProxyModel(); + + QVariant headerData(int section, Qt::Orientation orientation, int role) const; +}; + +#endif // PLUGINSPROXYMODEL_HPP diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index f87937228..fcf6f8b8a 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -21,8 +21,6 @@ GameSettings::~GameSettings() void GameSettings::validatePaths() { - qDebug() << "validate paths!"; - if (mSettings.isEmpty()) return; @@ -35,9 +33,6 @@ void GameSettings::validatePaths() // Parse the data dirs to convert the tokenized paths mCfgMgr.processPaths(dataDirs); - -// // Replace the existing data paths with valid untokenized ones -// mSettings.remove(QString("data")); mDataDirs.clear(); for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { @@ -59,7 +54,6 @@ void GameSettings::validatePaths() dataDirs.push_back(Files::PathContainer::value_type(local.toStdString())); mCfgMgr.processPaths(dataDirs); -// mSettings.remove(QString("data-local")); if (!dataDirs.empty()) { QString path = QString::fromStdString(dataDirs.front().string()); @@ -92,23 +86,21 @@ bool GameSettings::readFile(QTextStream &stream) if (line.isEmpty() || line.startsWith("#")) continue; - qDebug() << "line: " << line; if (keyRe.indexIn(line) != -1) { QString key = keyRe.cap(1).simplified(); QString value = keyRe.cap(2).simplified(); - qDebug() << "key: " << key; - // There can be multiple data keys - if (key == QLatin1String("data")) { + // There can be multiple keys + if (key == QLatin1String("data") || + key == QLatin1String("master") || + key == QLatin1String("plugin")) + { // Remove keys from previous config and overwrite them mSettings.remove(key); QStringList values = cache.values(key); - if (!values.contains(value)) { - // Do not insert duplicate values - qDebug() << "values does not contain: " << value << values; + if (!values.contains(value)) // Do not insert duplicate values cache.insertMulti(key, value); - } } else { cache.insert(key, value); } @@ -137,23 +129,42 @@ bool GameSettings::readFile(QTextStream &stream) // Merge the changed keys with those which didn't mSettings.unite(cache); validatePaths(); - qDebug() << mSettings; + return true; } bool GameSettings::writeFile(QTextStream &stream) { + // Iterate in reverse order to preserve insertion order QMapIterator i(mSettings); - while (i.hasNext()) { - i.next(); + i.toBack(); - // Quote values with spaces - if (i.value().contains(" ")) { - stream << i.key() << "=\"" << i.value() << "\"\n"; - } else { - stream << i.key() << "=" << i.value() << "\n"; + while (i.hasPrevious()) { + i.previous(); + + if (i.key() == QLatin1String("master") || i.key() == QLatin1String("plugin")) + continue; + + // Quote paths with spaces + if (i.key() == QLatin1String("data") || i.key() == QLatin1String("data")) { + if (i.value().contains(" ")) { + stream << i.key() << "=\"" << i.value() << "\"\n"; + continue; + } } + stream << i.key() << "=" << i.value() << "\n"; + + } + + QStringList masters = mSettings.values(QString("master")); + for (int i = masters.count(); i--;) { + stream << "master=" << masters.at(i) << "\n"; + } + + QStringList plugins = mSettings.values(QString("plugin")); + for (int i = plugins.count(); i--;) { + stream << "plugin=" << plugins.at(i) << "\n"; } return true; diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index 07502ea02..e9730c235 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -26,7 +26,6 @@ QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags) QStringList keys = settings.keys(); foreach (const QString ¤tKey, keys) { - qDebug() << "key is: " << currentKey << "value: " << settings.value(currentKey); if (currentKey.startsWith(key)) result.append(settings.value(currentKey)); } @@ -38,16 +37,15 @@ QStringList LauncherSettings::values(const QString &key, Qt::MatchFlags flags) QStringList LauncherSettings::subKeys(const QString &key) { QMap settings = SettingsBase::getSettings(); - QStringList keys = settings.keys(); + QStringList keys = settings.uniqueKeys(); QRegExp keyRe("(.+)/"); QStringList result; foreach (const QString ¤tKey, keys) { - qDebug() << "key is: " << currentKey; + if (keyRe.indexIn(currentKey) != -1) { - qDebug() << "text: " << keyRe.cap(1) << keyRe.cap(2); QString prefixedKey = keyRe.cap(1); if(prefixedKey.startsWith(key)) { @@ -55,16 +53,11 @@ QStringList LauncherSettings::subKeys(const QString &key) QString subKey = prefixedKey.remove(key); if (!subKey.isEmpty()) result.append(subKey); - //qDebug() << keyRe.cap(2).simplified(); } - } else { - qDebug() << "no match"; } } result.removeDuplicates(); - qDebug() << result; - return result; } @@ -75,8 +68,10 @@ bool LauncherSettings::writeFile(QTextStream &stream) QMap settings = SettingsBase::getSettings(); QMapIterator i(settings); - while (i.hasNext()) { - i.next(); + i.toBack(); + + while (i.hasPrevious()) { + i.previous(); QString prefix; QString key; diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index e70bc0d72..321426eed 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -75,7 +75,6 @@ public: QStringList values = mCache.values(key); if (!values.contains(value)) { - // QMap will replace the value if key exists, QMultiMap creates a new one mCache.insertMulti(key, value); } } @@ -96,7 +95,6 @@ public: // Merge the changed keys with those which didn't mSettings.unite(mCache); - qDebug() << mSettings; return true; } diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 036394800..4e9b69dc2 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -229,10 +229,29 @@ bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2) return e1->fileName().toLower() < e2->fileName().toLower(); } +bool lessThanDate(const EsmFile *e1, const EsmFile *e2) +{ + if (e1->modified().toString(Qt::ISODate) < e2->modified().toString(Qt::ISODate)) { + return true; + } else { + return false; + } +// if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) +// return false; + +// return e1->fileName().toLower() < e2->fileName().toLower(); +} + void DataFilesModel::sort(int column, Qt::SortOrder order) { emit layoutAboutToBeChanged(); - qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile); + + if (column == 3) { + qSort(mFiles.begin(), mFiles.end(), lessThanDate); + } else { + qSort(mFiles.begin(), mFiles.end(), lessThanEsmFile); + } + emit layoutChanged(); } From 66743ecee70623d2d97291af7268fdcbf3a614e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 07:00:22 -0800 Subject: [PATCH 678/916] Remove some unused trace fields --- libs/openengine/bullet/trace.cpp | 39 +++++--------------------------- libs/openengine/bullet/trace.h | 3 --- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 618f6ee65..2f52d669a 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -29,14 +29,12 @@ struct NewPhysTraceResults Ogre::Vector3 endPos; Ogre::Vector3 hitNormal; float fraction; - bool startSolid; //const Object* hitObj; }; -template -static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, - OEngine::Physic::PhysicEngine* enginePass) +static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, + const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, + OEngine::Physic::PhysicEngine* enginePass) { const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); @@ -49,7 +47,7 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); - newTraceCallback.m_collisionFilterMask = (traceType == collisionWorldTrace) ? Only_Collision : Only_Pickup; + newTraceCallback.m_collisionFilterMask = Only_Collision; enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); @@ -66,24 +64,6 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve out->endPos.y = tracehitpos.y(); out->endPos.z = tracehitpos.z(); - // StartSolid test: - { - out->startSolid = false; - if(isInterior) - { - // If inside and out of the tree, we're solid - btVector3 aabbMin, aabbMax; - enginePass->broadphase->getBroadphaseAabb(aabbMin, aabbMax); - btVector3 point(start.x, start.y, start.z); - if(!TestPointAgainstAabb2(aabbMin, aabbMax, point)) - { - //We're solid - //THIS NEEDS TO BE TURNED OFF IF WE WANT FALLING IN EXTERIORS TO WORK CORRECTLY!!!!!!! - //out->startSolid = true; - } - } - } - return newTraceCallback.hasHit(); } @@ -91,15 +71,8 @@ static const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Ve void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object { NewPhysTraceResults out; - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, - Ogre::Vector3(0.0f, 0.0f, 0.0f), - isInterior, enginePass); - if (out.fraction < 0.001f) - results->startsolid = true; - else - results->startsolid = false; - results->allsolid = out.startSolid; - + bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), + isInterior, enginePass); if(!hasHit) { results->endpos = end; diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 7b17da178..34ecb7454 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -19,9 +19,6 @@ struct traceResults Ogre::Vector3 planenormal; float fraction; - - bool allsolid; - bool startsolid; }; void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); From 2172fb42298a4faddc7a0ae2a37a04aa3a4e15b1 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 19 Feb 2013 16:41:33 +0100 Subject: [PATCH 679/916] Added checkable message box class --- apps/launcher/CMakeLists.txt | 5 +- apps/launcher/utils/checkablemessagebox.cpp | 243 ++++++++++++++++++++ apps/launcher/utils/checkablemessagebox.hpp | 71 ++++++ 3 files changed, 318 insertions(+), 1 deletion(-) create mode 100644 apps/launcher/utils/checkablemessagebox.cpp create mode 100644 apps/launcher/utils/checkablemessagebox.hpp diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 59cccad5f..b2e6c7009 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -11,6 +11,7 @@ set(LAUNCHER settings/graphicssettings.cpp settings/launchersettings.cpp + utils/checkablemessagebox.cpp utils/comboboxlineedit.cpp utils/profilescombobox.cpp utils/textinputdialog.cpp @@ -31,7 +32,8 @@ set(LAUNCHER_HEADER settings/launchersettings.hpp settings/settingsbase.hpp - utils/comboboxlineedit.cpp + utils/checkablemessagebox.hpp + utils/comboboxlineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp ) @@ -45,6 +47,7 @@ set(LAUNCHER_HEADER_MOC model/pluginsproxymodel.hpp + utils/checkablemessagebox.hpp utils/comboboxlineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp diff --git a/apps/launcher/utils/checkablemessagebox.cpp b/apps/launcher/utils/checkablemessagebox.cpp new file mode 100644 index 000000000..8aa01d101 --- /dev/null +++ b/apps/launcher/utils/checkablemessagebox.cpp @@ -0,0 +1,243 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "checkablemessagebox.hpp" + + +/* + class CheckableMessageBox + Modified from the one used in Qt Creator + + A messagebox suitable for questions with a + "Do not ask me again" checkbox. + + Emulates the QMessageBox API with + static conveniences. The message label can open external URLs. +*/ + + +class CheckableMessageBoxPrivate +{ +public: + CheckableMessageBoxPrivate(QDialog *q) + : clickedButton(0) + { + QSizePolicy sizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + + pixmapLabel = new QLabel(q); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(pixmapLabel->sizePolicy().hasHeightForWidth()); + pixmapLabel->setSizePolicy(sizePolicy); + pixmapLabel->setVisible(false); + + QSpacerItem *pixmapSpacer = + new QSpacerItem(0, 5, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); + + messageLabel = new QLabel(q); + messageLabel->setMinimumSize(QSize(300, 0)); + messageLabel->setWordWrap(true); + messageLabel->setOpenExternalLinks(true); + messageLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse); + + QSpacerItem *checkBoxRightSpacer = + new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum); + QSpacerItem *buttonSpacer = + new QSpacerItem(0, 1, QSizePolicy::Minimum, QSizePolicy::Minimum); + + checkBox = new QCheckBox(q); + checkBox->setText(CheckableMessageBox::tr("Do not ask again")); + + buttonBox = new QDialogButtonBox(q); + buttonBox->setOrientation(Qt::Horizontal); + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + + QVBoxLayout *verticalLayout = new QVBoxLayout(); + verticalLayout->addWidget(pixmapLabel); + verticalLayout->addItem(pixmapSpacer); + + QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); + horizontalLayout_2->addLayout(verticalLayout); + horizontalLayout_2->addWidget(messageLabel); + + QHBoxLayout *horizontalLayout = new QHBoxLayout(); + horizontalLayout->addWidget(checkBox); + horizontalLayout->addItem(checkBoxRightSpacer); + + QVBoxLayout *verticalLayout_2 = new QVBoxLayout(q); + verticalLayout_2->addLayout(horizontalLayout_2); + verticalLayout_2->addLayout(horizontalLayout); + verticalLayout_2->addItem(buttonSpacer); + verticalLayout_2->addWidget(buttonBox); + } + + QLabel *pixmapLabel; + QLabel *messageLabel; + QCheckBox *checkBox; + QDialogButtonBox *buttonBox; + QAbstractButton *clickedButton; +}; + +CheckableMessageBox::CheckableMessageBox(QWidget *parent) : + QDialog(parent), + d(new CheckableMessageBoxPrivate(this)) +{ + setModal(true); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + connect(d->buttonBox, SIGNAL(accepted()), SLOT(accept())); + connect(d->buttonBox, SIGNAL(rejected()), SLOT(reject())); + connect(d->buttonBox, SIGNAL(clicked(QAbstractButton*)), + SLOT(slotClicked(QAbstractButton*))); +} + +CheckableMessageBox::~CheckableMessageBox() +{ + delete d; +} + +void CheckableMessageBox::slotClicked(QAbstractButton *b) +{ + d->clickedButton = b; +} + +QAbstractButton *CheckableMessageBox::clickedButton() const +{ + return d->clickedButton; +} + +QDialogButtonBox::StandardButton CheckableMessageBox::clickedStandardButton() const +{ + if (d->clickedButton) + return d->buttonBox->standardButton(d->clickedButton); + return QDialogButtonBox::NoButton; +} + +QString CheckableMessageBox::text() const +{ + return d->messageLabel->text(); +} + +void CheckableMessageBox::setText(const QString &t) +{ + d->messageLabel->setText(t); +} + +QPixmap CheckableMessageBox::iconPixmap() const +{ + if (const QPixmap *p = d->pixmapLabel->pixmap()) + return QPixmap(*p); + return QPixmap(); +} + +void CheckableMessageBox::setIconPixmap(const QPixmap &p) +{ + d->pixmapLabel->setPixmap(p); + d->pixmapLabel->setVisible(!p.isNull()); +} + +bool CheckableMessageBox::isChecked() const +{ + return d->checkBox->isChecked(); +} + +void CheckableMessageBox::setChecked(bool s) +{ + d->checkBox->setChecked(s); +} + +QString CheckableMessageBox::checkBoxText() const +{ + return d->checkBox->text(); +} + +void CheckableMessageBox::setCheckBoxText(const QString &t) +{ + d->checkBox->setText(t); +} + +bool CheckableMessageBox::isCheckBoxVisible() const +{ + return d->checkBox->isVisible(); +} + +void CheckableMessageBox::setCheckBoxVisible(bool v) +{ + d->checkBox->setVisible(v); +} + +QDialogButtonBox::StandardButtons CheckableMessageBox::standardButtons() const +{ + return d->buttonBox->standardButtons(); +} + +void CheckableMessageBox::setStandardButtons(QDialogButtonBox::StandardButtons s) +{ + d->buttonBox->setStandardButtons(s); +} + +QPushButton *CheckableMessageBox::button(QDialogButtonBox::StandardButton b) const +{ + return d->buttonBox->button(b); +} + +QPushButton *CheckableMessageBox::addButton(const QString &text, QDialogButtonBox::ButtonRole role) +{ + return d->buttonBox->addButton(text, role); +} + +QDialogButtonBox::StandardButton CheckableMessageBox::defaultButton() const +{ + foreach (QAbstractButton *b, d->buttonBox->buttons()) + if (QPushButton *pb = qobject_cast(b)) + if (pb->isDefault()) + return d->buttonBox->standardButton(pb); + return QDialogButtonBox::NoButton; +} + +void CheckableMessageBox::setDefaultButton(QDialogButtonBox::StandardButton s) +{ + if (QPushButton *b = d->buttonBox->button(s)) { + b->setDefault(true); + b->setFocus(); + } +} + +QDialogButtonBox::StandardButton +CheckableMessageBox::question(QWidget *parent, + const QString &title, + const QString &question, + const QString &checkBoxText, + bool *checkBoxSetting, + QDialogButtonBox::StandardButtons buttons, + QDialogButtonBox::StandardButton defaultButton) +{ + CheckableMessageBox mb(parent); + mb.setWindowTitle(title); + mb.setIconPixmap(QMessageBox::standardIcon(QMessageBox::Question)); + mb.setText(question); + mb.setCheckBoxText(checkBoxText); + mb.setChecked(*checkBoxSetting); + mb.setStandardButtons(buttons); + mb.setDefaultButton(defaultButton); + mb.exec(); + *checkBoxSetting = mb.isChecked(); + return mb.clickedStandardButton(); +} + +QMessageBox::StandardButton CheckableMessageBox::dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton db) +{ + return static_cast(int(db)); +} diff --git a/apps/launcher/utils/checkablemessagebox.hpp b/apps/launcher/utils/checkablemessagebox.hpp new file mode 100644 index 000000000..ceb437d4d --- /dev/null +++ b/apps/launcher/utils/checkablemessagebox.hpp @@ -0,0 +1,71 @@ +#ifndef CHECKABLEMESSAGEBOX_HPP +#define CHECKABLEMESSAGEBOX_HPP + +#include +#include +#include + +class CheckableMessageBoxPrivate; + +class CheckableMessageBox : public QDialog +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap) + Q_PROPERTY(bool isChecked READ isChecked WRITE setChecked) + Q_PROPERTY(QString checkBoxText READ checkBoxText WRITE setCheckBoxText) + Q_PROPERTY(QDialogButtonBox::StandardButtons buttons READ standardButtons WRITE setStandardButtons) + Q_PROPERTY(QDialogButtonBox::StandardButton defaultButton READ defaultButton WRITE setDefaultButton) + +public: + explicit CheckableMessageBox(QWidget *parent); + virtual ~CheckableMessageBox(); + + static QDialogButtonBox::StandardButton + question(QWidget *parent, + const QString &title, + const QString &question, + const QString &checkBoxText, + bool *checkBoxSetting, + QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No, + QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No); + + QString text() const; + void setText(const QString &); + + bool isChecked() const; + void setChecked(bool s); + + QString checkBoxText() const; + void setCheckBoxText(const QString &); + + bool isCheckBoxVisible() const; + void setCheckBoxVisible(bool); + + QDialogButtonBox::StandardButtons standardButtons() const; + void setStandardButtons(QDialogButtonBox::StandardButtons s); + QPushButton *button(QDialogButtonBox::StandardButton b) const; + QPushButton *addButton(const QString &text, QDialogButtonBox::ButtonRole role); + + QDialogButtonBox::StandardButton defaultButton() const; + void setDefaultButton(QDialogButtonBox::StandardButton s); + + // See static QMessageBox::standardPixmap() + QPixmap iconPixmap() const; + void setIconPixmap (const QPixmap &p); + + // Query the result + QAbstractButton *clickedButton() const; + QDialogButtonBox::StandardButton clickedStandardButton() const; + + // Conversion convenience + static QMessageBox::StandardButton dialogButtonBoxToMessageBoxButton(QDialogButtonBox::StandardButton); + +private slots: + void slotClicked(QAbstractButton *b); + +private: + CheckableMessageBoxPrivate *d; +}; + +#endif // CHECKABLEMESSAGEBOX_HPP From 43d63929217c43092a56f7a07d1c78c6f15728d2 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 16 Feb 2013 20:56:17 +0100 Subject: [PATCH 680/916] Change the way pinnable window are made visible This ensure pinned window are not displayed in main menu, dialogue and container mode. --- apps/openmw/mwgui/window_pinnable_base.cpp | 10 ---------- apps/openmw/mwgui/window_pinnable_base.hpp | 1 - apps/openmw/mwgui/windowmanagerimp.cpp | 15 ++++++++++++++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index 4ddf49d27..2e66a4805 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -11,16 +11,6 @@ WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::Win t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed); } -void WindowPinnableBase::setVisible(bool b) -{ - // Pinned windows can not be hidden - if (mPinned && !b) - return; - - WindowBase::setVisible(b); - mVisible = b; -} - void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName) { if ("PinToggle" == eventName) diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index 250dde1f8..c577564c7 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -11,7 +11,6 @@ namespace MWGui { public: WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - void setVisible(bool b); bool pinned() { return mPinned; } private: diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e03b91216..39f7d0776 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -310,9 +310,16 @@ void WindowManager::updateVisible() setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); - // If in game mode, don't show anything. + // If in game mode, show only the pinned windows if (gameMode) + { + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + return; + } GuiMode mode = mGuiModes.back(); @@ -327,6 +334,12 @@ void WindowManager::updateVisible() mSettingsWindow->setVisible(true); break; case GM_Console: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + mConsole->enable(); break; case GM_Scroll: From 3ba3c71556d4e9b8abeb0fab8c329c86bec81082 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Feb 2013 02:56:07 +0100 Subject: [PATCH 681/916] Make the "lock window" button to change state visually --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/exposedwindow.cpp | 26 ++++++++++++++++++++++ apps/openmw/mwgui/exposedwindow.hpp | 26 ++++++++++++++++++++++ apps/openmw/mwgui/window_pinnable_base.cpp | 11 +++++++++ apps/openmw/mwgui/window_pinnable_base.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 2 ++ files/mygui/openmw_inventory_window.layout | 2 +- files/mygui/openmw_map_window.layout | 2 +- files/mygui/openmw_spell_window.layout | 2 +- files/mygui/openmw_stats_window.layout | 2 +- files/mygui/openmw_windows.skin.xml | 14 +++++++++++- 11 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 apps/openmw/mwgui/exposedwindow.cpp create mode 100644 apps/openmw/mwgui/exposedwindow.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index df679d4cb..3dd5ed45d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -30,7 +30,7 @@ add_openmw_dir (mwgui formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog trainingwindow travelwindow imagebutton + enchantingdialog trainingwindow travelwindow imagebutton exposedwindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/exposedwindow.cpp b/apps/openmw/mwgui/exposedwindow.cpp new file mode 100644 index 000000000..fa37568d7 --- /dev/null +++ b/apps/openmw/mwgui/exposedwindow.cpp @@ -0,0 +1,26 @@ +#include "exposedwindow.hpp" + +#include "MyGUI_Window.h" + +namespace MWGui +{ + MyGUI::VectorWidgetPtr ExposedWindow::getSkinWidgetsByName (const std::string &name) + { + return MyGUI::Widget::getSkinWidgetsByName (name); + } + + MyGUI::Widget* ExposedWindow::getSkinWidget(const std::string & _name, bool _throw) + { + MyGUI::VectorWidgetPtr widgets = getSkinWidgetsByName (_name); + + if (widgets.empty()) + { + MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' not found in skin of layout '" << getName() << "'"); + return nullptr; + } + else + { + return widgets[0]; + } + } +} diff --git a/apps/openmw/mwgui/exposedwindow.hpp b/apps/openmw/mwgui/exposedwindow.hpp new file mode 100644 index 000000000..906d0b406 --- /dev/null +++ b/apps/openmw/mwgui/exposedwindow.hpp @@ -0,0 +1,26 @@ +#ifndef MWGUI_EXPOSEDWINDOW_H +#define MWGUI_EXPOSEDWINDOW_H + +#include "MyGUI_Window.h" + +namespace MWGui +{ + + /** + * @brief subclass to provide access to some Widget internals. + */ + class ExposedWindow : public MyGUI::Window + { + MYGUI_RTTI_DERIVED(ExposedWindow) + + public: + MyGUI::VectorWidgetPtr getSkinWidgetsByName (const std::string &name); + + MyGUI::Widget* getSkinWidget(const std::string & _name, bool _throw = true); + ///< Get a widget defined in the inner skin of this window. + }; + +} + +#endif + diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index 2e66a4805..781c427ef 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -2,6 +2,8 @@ #include "../mwbase/windowmanager.hpp" +#include "exposedwindow.hpp" + using namespace MWGui; WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) @@ -9,6 +11,9 @@ WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::Win { MyGUI::WindowPtr t = static_cast(mMainWidget); t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed); + + ExposedWindow* window = static_cast(mMainWidget); + mPinButton = window->getSkinWidget ("Button"); } void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName) @@ -16,6 +21,12 @@ void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std: if ("PinToggle" == eventName) { mPinned = !mPinned; + + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); + onPinToggled(); } diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index c577564c7..7426b16fc 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -19,6 +19,7 @@ namespace MWGui protected: virtual void onPinToggled() = 0; + MyGUI::Widget* mPinButton; bool mPinned; bool mVisible; }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 39f7d0776..1dc11f2c4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -52,6 +52,7 @@ #include "enchantingdialog.hpp" #include "trainingwindow.hpp" #include "imagebutton.hpp" +#include "exposedwindow.hpp" using namespace MWGui; @@ -127,6 +128,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 3a60916f7..88cc5638d 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_map_window.layout b/files/mygui/openmw_map_window.layout index b5479b676..d4b87e60d 100644 --- a/files/mygui/openmw_map_window.layout +++ b/files/mygui/openmw_map_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_spell_window.layout b/files/mygui/openmw_spell_window.layout index d489f41b8..6c6629605 100644 --- a/files/mygui/openmw_spell_window.layout +++ b/files/mygui/openmw_spell_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index c2c8a5dae..55ee7b9da 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index a9eb23d68..72b686125 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -8,6 +8,18 @@ + + + + + + + + + + + + @@ -473,7 +485,7 @@ - + From 2dea86bbc7cb8b95415d626d1a8b90de894e1416 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Feb 2013 03:04:38 +0100 Subject: [PATCH 682/916] Make the "lock window" button appealing --- files/mygui/openmw_windows.skin.xml | 116 ++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 8 deletions(-) diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 72b686125..93aa8fd20 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -8,17 +8,117 @@ - - - - + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -485,7 +585,7 @@ - + From 3dc28baa287dd9d2169bace23bf89d2cb792e084 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Feb 2013 16:29:38 +0100 Subject: [PATCH 683/916] Remove "PinToggle" event from layout file --- apps/openmw/mwgui/window_pinnable_base.cpp | 24 ++++++++-------------- apps/openmw/mwgui/window_pinnable_base.hpp | 2 +- files/mygui/openmw_windows.skin.xml | 4 +--- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index 781c427ef..651b3a1e9 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -9,26 +9,20 @@ using namespace MWGui; WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) { - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowButtonPressed += MyGUI::newDelegate(this, &WindowPinnableBase::onWindowButtonPressed); - ExposedWindow* window = static_cast(mMainWidget); mPinButton = window->getSkinWidget ("Button"); + + mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); } -void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName) +void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) { - if ("PinToggle" == eventName) - { - mPinned = !mPinned; + mPinned = !mPinned; - if (mPinned) - mPinButton->changeWidgetSkin ("PinDown"); - else - mPinButton->changeWidgetSkin ("PinUp"); + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); - onPinToggled(); - } - - eventDone(this); + onPinToggled(); } diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index 7426b16fc..50259858e 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -14,7 +14,7 @@ namespace MWGui bool pinned() { return mPinned; } private: - void onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName); + void onPinButtonClicked(MyGUI::Widget* _sender); protected: virtual void onPinToggled() = 0; diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 93aa8fd20..73f68e80d 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -585,9 +585,7 @@ - - - + From f4749f10dadaf119fad8b3b85e0d74a23d72e781 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Feb 2013 05:35:52 +0100 Subject: [PATCH 684/916] NIF bullet loader fix for incorrect collision shapes (credit goes to Chris, he asked me to push this) --- components/nifbullet/bullet_nif_loader.cpp | 134 ++++++--------------- components/nifbullet/bullet_nif_loader.hpp | 18 +-- 2 files changed, 46 insertions(+), 106 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 9c6dafa34..a619bdda2 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -43,25 +43,14 @@ http://www.gnu.org/licenses/ . typedef unsigned char ubyte; -using namespace NifBullet; - +namespace NifBullet +{ ManualBulletShapeLoader::~ManualBulletShapeLoader() { } -btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 const &m) -{ - Ogre::Quaternion oquat(m); - btQuaternion quat; - quat.setW(oquat.w); - quat.setX(oquat.x); - quat.setY(oquat.y); - quat.setZ(oquat.z); - return quat; -} - btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) { return btVector3(v[0], v[1], v[2]); @@ -90,7 +79,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - // The first record is assumed to be the root node Nif::Record *r = nif.getRecord(0); assert(r != NULL); @@ -106,13 +94,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool hasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(node,0,NULL,hasCollisionNode,false,false); + handleNode(node,0,hasCollisionNode,false,false); //if collide = false, then it does a second pass which create a shape for raycasting. if(cShape->mCollide == false) - { - handleNode(node,0,NULL,hasCollisionNode,false,true); - } + handleNode(node,0,hasCollisionNode,false,true); //cShape->collide = hasCollisionNode&&cShape->collide; @@ -129,9 +115,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) delete m_meshInterface; } }; + if(mBoundingBox != NULL) cShape->Shape = mBoundingBox; - else { currentShape = new TriangleMeshShape(mTriMesh,true); @@ -141,34 +127,30 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) { - if (node->recType == Nif::RC_NiNode) + if(node->recType == Nif::RC_RootCollisionNode) + return true; + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; ichildren; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) + if(!list[i].empty()) { - if(hasRootCollisionNode(list[i].getPtr())) return true;; + if(hasRootCollisionNode(list[i].getPtr())) + return true; } } } - else if (node->recType == Nif::RC_NiTriShape) - { - return false; - } - else if(node->recType == Nif::RC_RootCollisionNode) - { - return true; - } return false; } -void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) +void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, + bool hasCollisionNode, bool isCollisionNode, + bool raycastingOnly) { - // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. flags |= node->flags; @@ -209,70 +191,36 @@ void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, } } - Nif::Transformation childTrafo = node->trafo; - - if (parentTrafo) - { - - // Get a non-const reference to the node's data, since we're - // overwriting it. TODO: Is this necessary? - - // For both position and rotation we have that: - // final_vector = old_vector + old_rotation*new_vector*old_scale - childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale; - - // Merge the rotations together - childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation; - - // Scale - childTrafo.scale *= parentTrafo->scale; - - } - if(node->hasBounds) { - - - btVector3 boxsize = getbtVector(node->boundXYZ); cShape->boxTranslation = node->boundPos; cShape->boxRotation = node->boundRot; - - mBoundingBox = new btBoxShape(boxsize); + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); } - - // For NiNodes, loop through children - if (node->recType == Nif::RC_NiNode) - { - Nif::NodeList const &list = ((Nif::NiNode const *)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) + if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->mCollide = !(flags&0x800); - handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); + handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); } - else if(node->recType == Nif::RC_RootCollisionNode) + + // For NiNodes, loop through children + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_RootCollisionNode); + + const Nif::NodeList &list = ninode->children; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) - handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly); + if(!list[i].empty()) + handleNode(list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycastingOnly); } } } -void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, - bool raycastingOnly) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, + bool raycastingOnly) { assert(shape != NULL); @@ -296,18 +244,14 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int return; - Nif::NiTriShapeData *data = shape->data.getPtr(); - + const Nif::NiTriShapeData *data = shape->data.getPtr(); const std::vector &vertices = data->vertices; - const Ogre::Matrix3 &rot = shape->trafo.rotation; - const Ogre::Vector3 &pos = shape->trafo.pos; - float scale = shape->trafo.scale * parentScale; - short* triangles = &data->triangles[0]; + const short *triangles = &data->triangles[0]; for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1 = pos + rot*vertices[triangles[i+0]]*scale; - Ogre::Vector3 b2 = pos + rot*vertices[triangles[i+1]]*scale; - Ogre::Vector3 b3 = pos + rot*vertices[triangles[i+2]]*scale; + Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; + Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; + Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } @@ -320,3 +264,5 @@ void ManualBulletShapeLoader::load(const std::string &name,const std::string &gr return; OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this); } + +} // namespace NifBullet diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index 520878ce1..0629b208d 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -51,19 +51,18 @@ namespace NifBullet class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader { public: - ManualBulletShapeLoader():resourceGroup("General"){} virtual ~ManualBulletShapeLoader(); - void warn(std::string msg) + void warn(const std::string &msg) { std::cerr << "NIFLoader: Warn:" << msg << "\n"; } - void fail(std::string msg) + void fail(const std::string &msg) { std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - assert(1); + abort(); } /** @@ -79,31 +78,26 @@ public: void load(const std::string &name,const std::string &group); private: - btQuaternion getbtQuat(Ogre::Matrix3 const &m); - btVector3 getbtVector(Ogre::Vector3 const &v); /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); + void handleNode(Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycastingOnly); /** *Helper function */ - bool hasRootCollisionNode(Nif::Node const * node); + bool hasRootCollisionNode(const Nif::Node *node); /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycastingOnly); std::string resourceName; std::string resourceGroup; - - OEngine::Physic::BulletShape* cShape;//current shape btTriangleMesh *mTriMesh; btBoxShape *mBoundingBox; From 6ae00be8a32966c2f7a9f433464e565a70f488db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 19 Feb 2013 22:28:15 -0800 Subject: [PATCH 685/916] Fix nifbullet shape transformation --- components/nifbullet/bullet_nif_loader.cpp | 134 ++++++--------------- components/nifbullet/bullet_nif_loader.hpp | 18 +-- 2 files changed, 46 insertions(+), 106 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 9c6dafa34..a619bdda2 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -43,25 +43,14 @@ http://www.gnu.org/licenses/ . typedef unsigned char ubyte; -using namespace NifBullet; - +namespace NifBullet +{ ManualBulletShapeLoader::~ManualBulletShapeLoader() { } -btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 const &m) -{ - Ogre::Quaternion oquat(m); - btQuaternion quat; - quat.setW(oquat.w); - quat.setX(oquat.x); - quat.setY(oquat.y); - quat.setZ(oquat.z); - return quat; -} - btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 const &v) { return btVector3(v[0], v[1], v[2]); @@ -90,7 +79,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - // The first record is assumed to be the root node Nif::Record *r = nif.getRecord(0); assert(r != NULL); @@ -106,13 +94,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool hasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(node,0,NULL,hasCollisionNode,false,false); + handleNode(node,0,hasCollisionNode,false,false); //if collide = false, then it does a second pass which create a shape for raycasting. if(cShape->mCollide == false) - { - handleNode(node,0,NULL,hasCollisionNode,false,true); - } + handleNode(node,0,hasCollisionNode,false,true); //cShape->collide = hasCollisionNode&&cShape->collide; @@ -129,9 +115,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) delete m_meshInterface; } }; + if(mBoundingBox != NULL) cShape->Shape = mBoundingBox; - else { currentShape = new TriangleMeshShape(mTriMesh,true); @@ -141,34 +127,30 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) { - if (node->recType == Nif::RC_NiNode) + if(node->recType == Nif::RC_RootCollisionNode) + return true; + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; ichildren; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) + if(!list[i].empty()) { - if(hasRootCollisionNode(list[i].getPtr())) return true;; + if(hasRootCollisionNode(list[i].getPtr())) + return true; } } } - else if (node->recType == Nif::RC_NiTriShape) - { - return false; - } - else if(node->recType == Nif::RC_RootCollisionNode) - { - return true; - } return false; } -void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *parentTrafo,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly) +void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, + bool hasCollisionNode, bool isCollisionNode, + bool raycastingOnly) { - // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. flags |= node->flags; @@ -209,70 +191,36 @@ void ManualBulletShapeLoader::handleNode(Nif::Node const *node, int flags, } } - Nif::Transformation childTrafo = node->trafo; - - if (parentTrafo) - { - - // Get a non-const reference to the node's data, since we're - // overwriting it. TODO: Is this necessary? - - // For both position and rotation we have that: - // final_vector = old_vector + old_rotation*new_vector*old_scale - childTrafo.pos = parentTrafo->pos + parentTrafo->rotation*childTrafo.pos*parentTrafo->scale; - - // Merge the rotations together - childTrafo.rotation = parentTrafo->rotation * childTrafo.rotation; - - // Scale - childTrafo.scale *= parentTrafo->scale; - - } - if(node->hasBounds) { - - - btVector3 boxsize = getbtVector(node->boundXYZ); cShape->boxTranslation = node->boundPos; cShape->boxRotation = node->boundRot; - - mBoundingBox = new btBoxShape(boxsize); + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); } - - // For NiNodes, loop through children - if (node->recType == Nif::RC_NiNode) - { - Nif::NodeList const &list = ((Nif::NiNode const *)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) + if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->mCollide = !(flags&0x800); - handleNiTriShape(dynamic_cast(node), flags,childTrafo.rotation,childTrafo.pos,childTrafo.scale,raycastingOnly); + handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); } - else if(node->recType == Nif::RC_RootCollisionNode) + + // For NiNodes, loop through children + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - Nif::NodeList &list = ((Nif::NiNode*)node)->children; - int n = list.length(); - for (int i=0; irecType == Nif::RC_RootCollisionNode); + + const Nif::NodeList &list = ninode->children; + for(size_t i = 0;i < list.length();i++) { - if (!list[i].empty()) - handleNode(list[i].getPtr(), flags,&childTrafo, hasCollisionNode,true,raycastingOnly); + if(!list[i].empty()) + handleNode(list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycastingOnly); } } } -void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale, - bool raycastingOnly) +void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, + bool raycastingOnly) { assert(shape != NULL); @@ -296,18 +244,14 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape const *shape, int return; - Nif::NiTriShapeData *data = shape->data.getPtr(); - + const Nif::NiTriShapeData *data = shape->data.getPtr(); const std::vector &vertices = data->vertices; - const Ogre::Matrix3 &rot = shape->trafo.rotation; - const Ogre::Vector3 &pos = shape->trafo.pos; - float scale = shape->trafo.scale * parentScale; - short* triangles = &data->triangles[0]; + const short *triangles = &data->triangles[0]; for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1 = pos + rot*vertices[triangles[i+0]]*scale; - Ogre::Vector3 b2 = pos + rot*vertices[triangles[i+1]]*scale; - Ogre::Vector3 b3 = pos + rot*vertices[triangles[i+2]]*scale; + Ogre::Vector3 b1 = transform*vertices[triangles[i+0]]; + Ogre::Vector3 b2 = transform*vertices[triangles[i+1]]; + Ogre::Vector3 b3 = transform*vertices[triangles[i+2]]; mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } @@ -320,3 +264,5 @@ void ManualBulletShapeLoader::load(const std::string &name,const std::string &gr return; OEngine::Physic::BulletShapeManager::getSingleton().create(name,group,true,this); } + +} // namespace NifBullet diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index 520878ce1..0629b208d 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -51,19 +51,18 @@ namespace NifBullet class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader { public: - ManualBulletShapeLoader():resourceGroup("General"){} virtual ~ManualBulletShapeLoader(); - void warn(std::string msg) + void warn(const std::string &msg) { std::cerr << "NIFLoader: Warn:" << msg << "\n"; } - void fail(std::string msg) + void fail(const std::string &msg) { std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - assert(1); + abort(); } /** @@ -79,31 +78,26 @@ public: void load(const std::string &name,const std::string &group); private: - btQuaternion getbtQuat(Ogre::Matrix3 const &m); - btVector3 getbtVector(Ogre::Vector3 const &v); /** *Parse a node. */ - void handleNode(Nif::Node const *node, int flags, - const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); + void handleNode(Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycastingOnly); /** *Helper function */ - bool hasRootCollisionNode(Nif::Node const * node); + bool hasRootCollisionNode(const Nif::Node *node); /** *convert a NiTriShape to a bullet trishape. */ - void handleNiTriShape(Nif::NiTriShape const *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); + void handleNiTriShape(const Nif::NiTriShape *shape, int flags, const Ogre::Matrix4 &transform, bool raycastingOnly); std::string resourceName; std::string resourceGroup; - - OEngine::Physic::BulletShape* cShape;//current shape btTriangleMesh *mTriMesh; btBoxShape *mBoundingBox; From cfdc820a1f6382be2c78c0a71f20fa2e7f893cd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 01:55:12 -0800 Subject: [PATCH 686/916] Make an actor fly when it has a levitate effect --- apps/openmw/mwworld/worldimp.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1a6630232..e75bd1677 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -12,6 +12,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" @@ -886,12 +888,14 @@ namespace MWWorld player = iter; continue; } - Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, !isSwimming(iter->first)); + Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, + !isSwimming(iter->first) && !isFlying(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { - Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, !isSwimming(player->first)); + Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, + !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } // the only purpose this has currently is to update the debug drawer @@ -1386,11 +1390,15 @@ namespace MWWorld World::isFlying(const MWWorld::Ptr &ptr) const { RefData &refdata = ptr.getRefData(); - /// \todo check for levitation effects const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(physactor && physactor->getCollisionMode()) - return false; - return true; + if(!physactor || !physactor->getCollisionMode()) + return true; + + const MWWorld::Class &cls = MWWorld::Class::get(ptr); + if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) + return true; + + return false; } bool From 617158afcd43efc533fb49e07e736df60fcf6696 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 02:32:48 -0800 Subject: [PATCH 687/916] Ensure updated skeleton bone placement matches in world space Objects attached to actors (shirts, robes, etc) do not require the same node hierarchy as the character root. So to ensure proper placement, we need to set the bone target's derived transformation using the source bone's derived transformation (which in turn means we need to work up from the root, to ensure the bone's parents are properly placed). --- apps/openmw/mwrender/animation.cpp | 42 +++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 330045423..f4b618866 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -197,19 +197,41 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } +static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) +{ + if(skelsrc->hasBone(bone->getName())) + { + Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); + if(!srcbone->getParent() || !bone->getParent()) + { + bone->setOrientation(srcbone->getOrientation()); + bone->setPosition(srcbone->getPosition()); + bone->setScale(srcbone->getScale()); + } + else + { + bone->_setDerivedOrientation(srcbone->_getDerivedOrientation()); + bone->_setDerivedPosition(srcbone->_getDerivedPosition()); + bone->setScale(Ogre::Vector3::UNIT_SCALE); + } + } + else + { + // No matching bone in the source. Make sure it stays properly offset + // from its parent. + bone->resetToInitialState(); + } + + Ogre::Node::ChildNodeIterator boneiter = bone->getChildIterator(); + while(boneiter.hasMoreElements()) + updateBoneTree(skelsrc, static_cast(boneiter.getNext())); +} + void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel) { - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::Skeleton::BoneIterator boneiter = skel->getRootBoneIterator(); while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - if(!skelsrc->hasBone(bone->getName())) - continue; - Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); - bone->setOrientation(srcbone->getOrientation()); - bone->setPosition(srcbone->getPosition()); - bone->setScale(srcbone->getScale()); - } + updateBoneTree(skelsrc, boneiter.getNext()); } From fe6fa9ebe745ca2bb2cbe2b70e82eb150a50575d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 04:14:52 -0800 Subject: [PATCH 688/916] Simplify newtrace a bit --- apps/openmw/mwworld/physicssystem.cpp | 15 ++++---- libs/openengine/bullet/trace.cpp | 51 ++++++--------------------- libs/openengine/bullet/trace.h | 2 +- 3 files changed, 18 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 5552bd749..0b9e13fb7 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -34,18 +34,18 @@ namespace MWWorld { private: static bool stepMove(Ogre::Vector3& position, const Ogre::Vector3 &velocity, float remainingTime, - float verticalRotation, const Ogre::Vector3 &halfExtents, bool isInterior, + const Ogre::Vector3 &halfExtents, bool isInterior, OEngine::Physic::PhysicEngine *engine) { traceResults trace; // no initialization needed newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, - halfExtents, verticalRotation, isInterior, engine); + halfExtents, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; - newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); if(getSlope(trace.planenormal) < sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. @@ -105,7 +105,6 @@ namespace MWWorld bool onground = false; float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); - float verticalRotation = physicActor->getRotation().getYaw().valueDegrees(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); Ogre::Vector3 velocity; @@ -120,7 +119,7 @@ namespace MWWorld { if(!(movement.z > 0.0f)) { - newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, position, position-Ogre::Vector3(0,0,4), halfExtents, isInterior, engine); if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) onground = true; } @@ -145,7 +144,7 @@ namespace MWWorld int iterations = 0; do { // trace to where character would go if there were no obstructions - newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; currentNormal = trace.planenormal; remainingTime = remainingTime * (1.0f-trace.fraction); @@ -157,7 +156,7 @@ namespace MWWorld if(getSlope(currentNormal) > sMaxSlope || currentNormal == lastNormal) { if((gravity && !onground) || - !stepMove(newPosition, velocity, remainingTime, verticalRotation, halfExtents, isInterior, engine)) + !stepMove(newPosition, velocity, remainingTime, halfExtents, isInterior, engine)) { Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); resultantDirection.normalise(); @@ -182,7 +181,7 @@ namespace MWWorld if(onground) { - newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, verticalRotation, isInterior, engine); + newtrace(&trace, newPosition, newPosition-Ogre::Vector3(0,0,sStepSize+4.0f), halfExtents, isInterior, engine); if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) newPosition.z = trace.endpos.z + 2.0f; else diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 2f52d669a..7664eb418 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -24,21 +24,11 @@ enum collaborativePhysicsType Both_Physics = 3 // This object has both kinds of physics (example: activators) }; -struct NewPhysTraceResults -{ - Ogre::Vector3 endPos; - Ogre::Vector3 hitNormal; - float fraction; - //const Object* hitObj; -}; - -static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& start, const Ogre::Vector3& end, - const Ogre::Vector3& BBHalfExtents, const Ogre::Vector3& rotation, bool isInterior, - OEngine::Physic::PhysicEngine* enginePass) +void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine *enginePass) //Traceobj was a Aedra Object { const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); - const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z + const btQuaternion btrot(0.0f, 0.0f, 0.0f); //y, x, z const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); @@ -46,43 +36,22 @@ static bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& const btTransform to(btrot, btend); btCollisionWorld::ClosestConvexResultCallback newTraceCallback(btstart, btend); - newTraceCallback.m_collisionFilterMask = Only_Collision; enginePass->dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); // Copy the hit data over to our trace results struct: - out->fraction = newTraceCallback.m_closestHitFraction; - - const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; - out->hitNormal.x = tracehitnormal.x(); - out->hitNormal.y = tracehitnormal.y(); - out->hitNormal.z = tracehitnormal.z(); - - const btVector3& tracehitpos = newTraceCallback.m_hitPointWorld; - out->endPos.x = tracehitpos.x(); - out->endPos.y = tracehitpos.y(); - out->endPos.z = tracehitpos.z(); - - return newTraceCallback.hasHit(); -} - - -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object -{ - NewPhysTraceResults out; - bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), - isInterior, enginePass); - if(!hasHit) + if(newTraceCallback.hasHit()) + { + const btVector3& tracehitnormal = newTraceCallback.m_hitNormalWorld; + results->fraction = newTraceCallback.m_closestHitFraction; + results->planenormal = Ogre::Vector3(tracehitnormal.x(), tracehitnormal.y(), tracehitnormal.z()); + results->endpos = (end-start)*results->fraction + start; + } + else { results->endpos = end; results->planenormal = Ogre::Vector3(0.0f, 0.0f, 1.0f); results->fraction = 1.0f; } - else - { - results->fraction = out.fraction; - results->planenormal = out.hitNormal; - results->endpos = (end-start)*results->fraction + start; - } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 34ecb7454..f484497d9 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -21,6 +21,6 @@ struct traceResults float fraction; }; -void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); +void newtrace(traceResults *results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, bool isInterior, OEngine::Physic::PhysicEngine* enginePass); #endif From b14def7c0951fc17eff0394be34304dcf6223ad2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 05:24:38 -0800 Subject: [PATCH 689/916] Set the character as being on the ground when colliding with a shallow enough slope --- apps/openmw/mwworld/physicssystem.cpp | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 0b9e13fb7..a61eebe2f 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -137,45 +137,43 @@ namespace MWWorld clipVelocity(clippedVelocity, trace.planenormal, 1.0f); } - Ogre::Vector3 lastNormal(0.0f); - Ogre::Vector3 currentNormal(0.0f); - Ogre::Vector3 up(0.0f, 0.0f, 1.0f); + const Ogre::Vector3 up(0.0f, 0.0f, 1.0f); Ogre::Vector3 newPosition = position; int iterations = 0; do { // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; - currentNormal = trace.planenormal; remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions if(trace.fraction < 1.0f) { //std::cout<<"angle: "< sMaxSlope || currentNormal == lastNormal) + if(getSlope(trace.planenormal) <= sMaxSlope) { + // We hit a slope we can walk on. Update velocity accordingly. + clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + // We're only on the ground if gravity is affecting us + onground = gravity; + } + else + { + // Can't walk on this. Try to step up onto it. if((gravity && !onground) || !stepMove(newPosition, velocity, remainingTime, halfExtents, isInterior, engine)) { - Ogre::Vector3 resultantDirection = currentNormal.crossProduct(up); + Ogre::Vector3 resultantDirection = trace.planenormal.crossProduct(up); resultantDirection.normalise(); clippedVelocity = velocity; projectVelocity(clippedVelocity, resultantDirection); // just this isn't enough sometimes. It's the same problem that causes steps to be necessary on even uphill terrain. - clippedVelocity += currentNormal*clippedVelocity.length()/50.0f; - //std::cout<< "clipped velocity: "< 0.0f); From 4eb8ea0c954740e2287c1c6c81b2a11fc2e11eca Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 07:51:36 -0800 Subject: [PATCH 690/916] Fix stepping and vertical force accumulation --- apps/openmw/mwworld/physicssystem.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a61eebe2f..9b9c9afea 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -39,14 +39,18 @@ namespace MWWorld { traceResults trace; // no initialization needed - newtrace(&trace, position+Ogre::Vector3(0.0f,0.0f,sStepSize), - position+Ogre::Vector3(0.0f,0.0f,sStepSize)+velocity*remainingTime, - halfExtents, isInterior, engine); + newtrace(&trace, position, position+Ogre::Vector3(0.0f,0.0f,sStepSize), + halfExtents, isInterior, engine); + if(trace.fraction == 0.0f) + return false; + + newtrace(&trace, trace.endpos, trace.endpos + velocity*remainingTime, + halfExtents, isInterior, engine); if(trace.fraction == 0.0f || (trace.fraction != 1.0f && getSlope(trace.planenormal) > sMaxSlope)) return false; newtrace(&trace, trace.endpos, trace.endpos-Ogre::Vector3(0.0f,0.0f,sStepSize), halfExtents, isInterior, engine); - if(getSlope(trace.planenormal) < sMaxSlope) + if(getSlope(trace.planenormal) <= sMaxSlope) { // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. position = trace.endpos; @@ -56,7 +60,7 @@ namespace MWWorld return false; } - static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce) + static void clipVelocity(Ogre::Vector3& inout, const Ogre::Vector3& normal, float overbounce=1.0f) { //Math stuff. Basically just project the velocity vector onto the plane represented by the normal. //More specifically, it projects velocity onto the normal, takes that result, multiplies it by overbounce and then subtracts it from velocity. @@ -134,7 +138,7 @@ namespace MWWorld { // if we're on the ground, force velocity to track it clippedVelocity.z = velocity.z = std::max(0.0f, velocity.z); - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal); } const Ogre::Vector3 up(0.0f, 0.0f, 1.0f); @@ -153,7 +157,7 @@ namespace MWWorld if(getSlope(trace.planenormal) <= sMaxSlope) { // We hit a slope we can walk on. Update velocity accordingly. - clipVelocity(clippedVelocity, trace.planenormal, 1.0f); + clipVelocity(clippedVelocity, trace.planenormal); // We're only on the ground if gravity is affecting us onground = gravity; } @@ -186,7 +190,7 @@ namespace MWWorld onground = false; } physicActor->setOnGround(onground); - physicActor->setVerticalForce(clippedVelocity.z - time*400.0f); + physicActor->setVerticalForce(clippedVelocity.z - time*627.2f); return newPosition; } From 18d01cd65a585abbaf1b7f197d2af283f922c7a8 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Wed, 20 Feb 2013 19:27:04 +0100 Subject: [PATCH 691/916] Implemented a first-run dialog to import Morrowind.ini settings --- apps/launcher/main.cpp | 166 +------- apps/launcher/maindialog.cpp | 427 +++++++++++++++++--- apps/launcher/maindialog.hpp | 31 +- apps/launcher/settings/gamesettings.cpp | 34 +- apps/launcher/settings/gamesettings.hpp | 5 + apps/launcher/utils/checkablemessagebox.cpp | 43 +- apps/launcher/utils/checkablemessagebox.hpp | 43 +- 7 files changed, 493 insertions(+), 256 deletions(-) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index ba84518c1..5d57dce55 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,23 +1,6 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include #include "maindialog.hpp" -#include "settings/gamesettings.hpp" -#include "settings/graphicssettings.hpp" -#include "settings/launchersettings.hpp" - int main(int argc, char *argv[]) { @@ -45,154 +28,7 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); - // Create setting file handlers - - Files::ConfigurationManager cfgMgr; - QString userPath = QString::fromStdString(cfgMgr.getUserPath().string()); - QString globalPath = QString::fromStdString(cfgMgr.getGlobalPath().string()); - - GameSettings gameSettings(cfgMgr); - GraphicsSettings graphicsSettings; - LauncherSettings launcherSettings; - - QStringList paths; - paths.append(userPath + QString("openmw.cfg")); - paths.append(QString("openmw.cfg")); - paths.append(globalPath + QString("openmw.cfg")); - - foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; - QFile file(path); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error opening OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - return 0; - } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - gameSettings.readFile(stream); - } - file.close(); - } - - if (gameSettings.getDataDirs().isEmpty()) - { - QMessageBox msgBox; - msgBox.setWindowTitle("Error detecting Morrowind installation"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(QObject::tr("
Could not find the Data Files location

\ - The directory containing the data files was not found.

\ - Press \"Browse...\" to specify the location manually.
")); - - QAbstractButton *dirSelectButton = - msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); - - msgBox.exec(); - - QString selectedFile; - if (msgBox.clickedButton() == dirSelectButton) { - selectedFile = QFileDialog::getOpenFileName( - NULL, - QObject::tr("Select master file"), - QDir::currentPath(), - QString("Morrowind master file (*.esm)")); - } - - if (selectedFile.isEmpty()) - return 0; // Cancel was clicked; - - qDebug() << selectedFile; - QFileInfo info(selectedFile); - - // Add the new dir to the settings file and to the data dir container - gameSettings.setValue(QString("data"), info.absolutePath()); - gameSettings.addDataDir(info.absolutePath()); - - } - - // On to the graphics settings - QFile localDefault(QString("settings-default.cfg")); - QFile globalDefault(globalPath + QString("settings-default.cfg")); - - if (!localDefault.exists() && !globalDefault.exists()) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error reading OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not find settings-default.cfg

\ - The problem may be due to an incomplete installation of OpenMW.
\ - Reinstalling OpenMW may resolve the problem.")); - msgBox.exec(); - return 0; - } - - paths.clear(); - paths.append(globalPath + QString("settings-default.cfg")); - paths.append(QString("settings-default.cfg")); - paths.append(userPath + QString("settings.cfg")); - - foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; - QFile file(path); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error opening OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - return 0; - } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - graphicsSettings.readFile(stream); - } - file.close(); - } - - // Now the launcher settings - paths.clear(); - paths.append(QString("launcher.cfg")); - paths.append(userPath + QString("launcher.cfg")); - - foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; - QFile file(path); - if (file.exists()) { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error opening OpenMW configuration file"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - return 0; - } - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - launcherSettings.readFile(stream); - } - file.close(); - } - - - MainDialog mainWin(gameSettings, graphicsSettings, launcherSettings); + MainDialog mainWin; if (mainWin.setup()) { mainWin.show(); diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 15f2690da..77526677b 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,9 +1,6 @@ #include -#include "settings/gamesettings.hpp" -#include "settings/graphicssettings.hpp" -#include "settings/launchersettings.hpp" - +#include "utils/checkablemessagebox.hpp" #include "utils/profilescombobox.hpp" #include "maindialog.hpp" @@ -11,13 +8,8 @@ #include "graphicspage.hpp" #include "datafilespage.hpp" -MainDialog::MainDialog(GameSettings &gameSettings, - GraphicsSettings &graphicsSettings, - LauncherSettings &launcherSettings) - : mGameSettings(gameSettings) - , mGraphicsSettings(graphicsSettings) - , mLauncherSettings(launcherSettings) - +MainDialog::MainDialog() + : mGameSettings(mCfgMgr) { QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); @@ -95,7 +87,6 @@ MainDialog::MainDialog(GameSettings &gameSettings, connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); createIcons(); - createPages(); } void MainDialog::createIcons() @@ -161,14 +152,148 @@ void MainDialog::createPages() } +bool MainDialog::showFirstRunDialog() +{ + CheckableMessageBox msgBox(this); + msgBox.setWindowTitle(tr("Morrowind installation detected")); + + QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion); + int size = QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize); + msgBox.setIconPixmap(icon.pixmap(size, size)); + + + QAbstractButton *importerButton = + msgBox.addButton(tr("Import"), QDialogButtonBox::AcceptRole); // ActionRole doesn't work?! + QAbstractButton *skipButton = + msgBox.addButton(tr("Skip"), QDialogButtonBox::RejectRole); + + Q_UNUSED(skipButton); // Surpress compiler unused warning + + msgBox.setStandardButtons(QDialogButtonBox::NoButton); + + msgBox.setText(tr("
An existing Morrowind installation was detected

\ + Would you like to import settings from Morrowind.ini?
")); + + msgBox.setCheckBoxText(tr("Include selected masters and plugins (creates a new profile)")); + msgBox.exec(); + + + if (msgBox.clickedButton() == importerButton) { + + QString iniPath; + + foreach (const QString &path, mGameSettings.getDataDirs()) { + QDir dir(path); + dir.setPath(dir.canonicalPath()); // Resolve symlinks + + if (!dir.cdUp()) + continue; // Cannot move from Data Files + + if (dir.exists(QString("Morrowind.ini"))) + iniPath = dir.absoluteFilePath(QString("Morrowind.ini")); + } + + if (iniPath.isEmpty()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error reading Morrowind configuration file")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not find Morrowind.ini

\ + The problem may be due to an incomplete installation of Morrowind.
\ + Reinstalling Morrowind may resolve the problem.")); + msgBox.exec(); + return false; + } + + // Create the file if it doesn't already exist, else the importer will fail + QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg"); + QFile file(path); + + if (!file.exists()) { + if (!file.open(QIODevice::ReadWrite)) { + // File cannot be created + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not open or create %0 for writing

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return false; + } + + file.close(); + } + + // Construct the arguments to run the importer + QStringList arguments; + + if (msgBox.isChecked()) + arguments.append(QString("-g")); + + arguments.append(iniPath); + arguments.append(path); + + if (!startProgram(QString("mwiniimport"), arguments, false)) + return false; + + // Re-read the game settings + mGameSettings.clear(); + + if (!setupGameSettings()) + return false; + + // Add a new profile + if (msgBox.isChecked()) { + qDebug() << "add a new profile"; + mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), QString("Imported")); + + mLauncherSettings.remove(QString("Profiles/Imported/master")); + mLauncherSettings.remove(QString("Profiles/Imported/plugin")); + + QStringList masters = mGameSettings.values(QString("master")); + QStringList plugins = mGameSettings.values(QString("plugin")); + + foreach (const QString &master, masters) { + mLauncherSettings.setMultiValue(QString("Profiles/Imported/master"), master); + } + + foreach (const QString &plugin, plugins) { + mLauncherSettings.setMultiValue(QString("Profiles/Imported/plugin"), plugin); + } + } + + } + + return true; +} bool MainDialog::setup() { - // Call this so we can exit on Ogre errors before mainwindow is shown - if (!mGraphicsPage->setupOgre()) { + if (!setupLauncherSettings()) return false; + + if (!setupGameSettings()) + return false; + + if (!setupGraphicsSettings()) + return false; + + // Check if we need to show the importer + if (mLauncherSettings.value(QString("General/firstrun"), QString("true")) == QLatin1String("true")) + { + if (!showFirstRunDialog()) + return false; } + // Now create the pages as they need the settings + createPages(); + + // Call this so we can exit on Ogre errors before mainwindow is shown + if (!mGraphicsPage->setupOgre()) + return false; + loadSettings(); return true; } @@ -181,6 +306,164 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) mPagesWidget->setCurrentIndex(mIconWidget->row(current)); } +bool MainDialog::setupLauncherSettings() +{ + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + + QStringList paths; + paths.append(QString("launcher.cfg")); + paths.append(userPath + QString("launcher.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return false; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mLauncherSettings.readFile(stream); + } + file.close(); + } + + return true; +} + +bool MainDialog::setupGameSettings() +{ + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); + + QStringList paths; + paths.append(userPath + QString("openmw.cfg")); + paths.append(QString("openmw.cfg")); + paths.append(globalPath + QString("openmw.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return false; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mGameSettings.readFile(stream); + } + file.close(); + } + + if (mGameSettings.getDataDirs().isEmpty()) + { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error detecting Morrowind installation")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(QObject::tr("
Could not find the Data Files location

\ + The directory containing the data files was not found.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + QString selectedFile; + if (msgBox.clickedButton() == dirSelectButton) { + selectedFile = QFileDialog::getOpenFileName( + NULL, + QObject::tr("Select master file"), + QDir::currentPath(), + QString(tr("Morrowind master file (*.esm)"))); + } + + if (selectedFile.isEmpty()) + return false; // Cancel was clicked; + + qDebug() << selectedFile; + QFileInfo info(selectedFile); + + // Add the new dir to the settings file and to the data dir container + mGameSettings.setValue(QString("data"), info.absolutePath()); + mGameSettings.addDataDir(info.absolutePath()); + + } + + return true; +} + +bool MainDialog::setupGraphicsSettings() +{ + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); + QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); + + QFile localDefault(QString("settings-default.cfg")); + QFile globalDefault(globalPath + QString("settings-default.cfg")); + + if (!localDefault.exists() && !globalDefault.exists()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error reading OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not find settings-default.cfg

\ + The problem may be due to an incomplete installation of OpenMW.
\ + Reinstalling OpenMW may resolve the problem.")); + msgBox.exec(); + return false; + } + + + QStringList paths; + paths.append(globalPath + QString("settings-default.cfg")); + paths.append(QString("settings-default.cfg")); + paths.append(userPath + QString("settings.cfg")); + + foreach (const QString &path, paths) { + qDebug() << "Loading: " << path; + QFile file(path); + if (file.exists()) { + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening OpenMW configuration file")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + return false; + } + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + + mGraphicsSettings.readFile(stream); + } + file.close(); + } + + return true; +} + void MainDialog::loadSettings() { int width = mLauncherSettings.value(QString("General/MainWindow/width")).toInt(); @@ -206,6 +489,9 @@ void MainDialog::saveSettings() mLauncherSettings.setValue(QString("General/MainWindow/posx"), posX); mLauncherSettings.setValue(QString("General/MainWindow/posy"), posY); + + mLauncherSettings.setValue(QString("General/firstrun"), QString("false")); + } void MainDialog::writeSettings() @@ -221,7 +507,7 @@ void MainDialog::writeSettings() if (!dir.exists()) { if (!dir.mkpath(userPath)) { QMessageBox msgBox; - msgBox.setWindowTitle("Error creating OpenMW configuration directory"); + msgBox.setWindowTitle(tr("Error creating OpenMW configuration directory")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not create %0

\ @@ -238,7 +524,7 @@ void MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not open or create %0 for writing

\ @@ -260,7 +546,7 @@ void MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created QMessageBox msgBox; - msgBox.setWindowTitle("Error writing OpenMW configuration file"); + msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not open or create %0 for writing

\ @@ -282,7 +568,7 @@ void MainDialog::writeSettings() if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { // File cannot be opened or created QMessageBox msgBox; - msgBox.setWindowTitle("Error writing Launcher configuration file"); + msgBox.setWindowTitle(tr("Error writing Launcher configuration file")); msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not open or create %0 for writing

\ @@ -308,69 +594,108 @@ void MainDialog::closeEvent(QCloseEvent *event) void MainDialog::play() { - // First do a write of all the configs, just to be sure - //mDataFilesPage->writeConfig(); - //mGraphicsPage->writeConfig(); saveSettings(); writeSettings(); + // Launch the game detached + startProgram(QString("openmw"), true); + qApp->quit(); +} + +bool MainDialog::startProgram(const QString &name, const QStringList &arguments, bool detached) +{ + QString path = name; #ifdef Q_OS_WIN - QString game = "./openmw.exe"; - QFile file(game); + path.append(QString(".exe")); #elif defined(Q_OS_MAC) QDir dir(QCoreApplication::applicationDirPath()); - QString game = dir.absoluteFilePath("openmw"); - QFile file(game); - game = "\"" + game + "\""; + path = dir.absoluteFilePath(name); #else - QString game = "./openmw"; - QFile file(game); + path.prepend(QString("./")); #endif + QFile file(path); + QProcess process; QFileInfo info(file); if (!file.exists()) { QMessageBox msgBox; - msgBox.setWindowTitle("Error starting OpenMW"); + msgBox.setWindowTitle(tr("Error starting executable")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not find OpenMW

\ - The OpenMW application is not found.
\ - Please make sure OpenMW is installed correctly and try again.
")); + msgBox.setText(tr("
Could not find %1

\ + The application is not found.
\ + Please make sure OpenMW is installed correctly and try again.
").arg(info.fileName())); msgBox.exec(); - return; + return false; } if (!info.isExecutable()) { QMessageBox msgBox; - msgBox.setWindowTitle("Error starting OpenMW"); + msgBox.setWindowTitle(tr("Error starting executable")); msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not start OpenMW

\ - The OpenMW application is not executable.
\ - Please make sure you have the right permissions and try again.
")); + msgBox.setText(tr("
Could not start %1

\ + The application is not executable.
\ + Please make sure you have the right permissions and try again.
").arg(info.fileName())); msgBox.exec(); - return; + return false; } - // Start the game - if (!process.startDetached(game)) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error starting OpenMW"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not start OpenMW

\ - An error occurred while starting OpenMW.

\ - Press \"Show Details...\" for more information.
")); - msgBox.setDetailedText(process.errorString()); - msgBox.exec(); + // Start the executable + if (detached) { + if (!process.startDetached(path, arguments)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error starting executable")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not start %1

\ + An error occurred while starting %1.

\ + Press \"Show Details...\" for more information.
").arg(info.fileName())); + msgBox.setDetailedText(process.errorString()); + msgBox.exec(); - return; + return false; + } } else { - qApp->quit(); + process.start(path, arguments); + if (!process.waitForFinished()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error starting executable")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not start %1

\ + An error occurred while starting %1.

\ + Press \"Show Details...\" for more information.
").arg(info.fileName())); + msgBox.setDetailedText(process.errorString()); + msgBox.exec(); + + return false; + } + + if (process.exitCode() != 0) { + QString error(process.readAllStandardError()); + error.append(tr("\nArguments:\n")); + error.append(arguments.join(" ")); + + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error running executable")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Executable %1 returned an error

\ + An error occurred while running %1.

\ + Press \"Show Details...\" for more information.
").arg(info.fileName())); + msgBox.setDetailedText(error); + msgBox.exec(); + + return false; + } } + + return true; + } diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 7167d101d..f221bd5e6 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -5,6 +5,10 @@ #include +#include "settings/gamesettings.hpp" +#include "settings/graphicssettings.hpp" +#include "settings/launchersettings.hpp" + class QListWidget; class QListWidgetItem; class QStackedWidget; @@ -16,20 +20,20 @@ class PlayPage; class GraphicsPage; class DataFilesPage; -class GameSettings; -class GraphicsSettings; -class LauncherSettings; - class MainDialog : public QMainWindow { Q_OBJECT public: - MainDialog(GameSettings &gameSettings, - GraphicsSettings &GraphicsSettings, - LauncherSettings &launcherSettings); + MainDialog(); + + +// GameSettings &gameSettings, +// GraphicsSettings &GraphicsSettings, +// LauncherSettings &launcherSettings); bool setup(); + bool showFirstRunDialog(); public slots: void changePage(QListWidgetItem *current, QListWidgetItem *previous); @@ -39,10 +43,17 @@ private: void createIcons(); void createPages(); + bool setupLauncherSettings(); + bool setupGameSettings(); + bool setupGraphicsSettings(); + void loadSettings(); void saveSettings(); void writeSettings(); + inline bool startProgram(const QString &name, bool detached = false) { return startProgram(name, QStringList(), detached); } + bool startProgram(const QString &name, const QStringList &arguments, bool detached = false); + void closeEvent(QCloseEvent *event); QListWidget *mIconWidget; @@ -54,9 +65,9 @@ private: Files::ConfigurationManager mCfgMgr; - GameSettings &mGameSettings; - GraphicsSettings &mGraphicsSettings; - LauncherSettings &mLauncherSettings; + GameSettings mGameSettings; + GraphicsSettings mGraphicsSettings; + LauncherSettings mLauncherSettings; }; diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index fcf6f8b8a..20ccebc97 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -25,6 +25,7 @@ void GameSettings::validatePaths() return; QStringList paths = mSettings.values(QString("data")); + qDebug() << "paths " << paths; Files::PathContainer dataDirs; foreach (const QString &path, paths) { @@ -63,9 +64,6 @@ void GameSettings::validatePaths() if (dir.exists()) mDataLocal = path; } - qDebug() << mSettings; - - } QStringList GameSettings::values(const QString &key, const QStringList &defaultValues) @@ -91,18 +89,24 @@ bool GameSettings::readFile(QTextStream &stream) QString key = keyRe.cap(1).simplified(); QString value = keyRe.cap(2).simplified(); - // There can be multiple keys - if (key == QLatin1String("data") || - key == QLatin1String("master") || - key == QLatin1String("plugin")) - { - // Remove keys from previous config and overwrite them - mSettings.remove(key); - QStringList values = cache.values(key); - if (!values.contains(value)) // Do not insert duplicate values - cache.insertMulti(key, value); - } else { - cache.insert(key, value); +// // There can be multiple keys +// if (key == QLatin1String("data") || +// key == QLatin1String("master") || +// key == QLatin1String("plugin")) +// { +// // Remove keys from previous config and overwrite them +// mSettings.remove(key); +// QStringList values = cache.values(key); +// if (!values.contains(value)) // Do not insert duplicate values +// cache.insertMulti(key, value); +// } else { +// cache.insert(key, value); +// } + mSettings.remove(key); + + QStringList values = cache.values(key); + if (!values.contains(value)) { + cache.insertMulti(key, value); } } } diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index 8aac1552d..fa62872b0 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -41,6 +41,11 @@ public: mSettings.remove(key); } + inline void clear() + { + mSettings.clear(); + } + inline QStringList getDataDirs() { return mDataDirs; } inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } inline QString getDataLocal() {return mDataLocal; } diff --git a/apps/launcher/utils/checkablemessagebox.cpp b/apps/launcher/utils/checkablemessagebox.cpp index 8aa01d101..990835594 100644 --- a/apps/launcher/utils/checkablemessagebox.cpp +++ b/apps/launcher/utils/checkablemessagebox.cpp @@ -1,3 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "checkablemessagebox.hpp" + #include #include @@ -14,21 +45,17 @@ #include #include -#include "checkablemessagebox.hpp" +/*! + \class Utils::CheckableMessageBox -/* - class CheckableMessageBox - Modified from the one used in Qt Creator - - A messagebox suitable for questions with a - "Do not ask me again" checkbox. + \brief A messagebox suitable for questions with a + "Do not ask me again" checkbox. Emulates the QMessageBox API with static conveniences. The message label can open external URLs. */ - class CheckableMessageBoxPrivate { public: diff --git a/apps/launcher/utils/checkablemessagebox.hpp b/apps/launcher/utils/checkablemessagebox.hpp index ceb437d4d..93fd43fe1 100644 --- a/apps/launcher/utils/checkablemessagebox.hpp +++ b/apps/launcher/utils/checkablemessagebox.hpp @@ -1,3 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + #ifndef CHECKABLEMESSAGEBOX_HPP #define CHECKABLEMESSAGEBOX_HPP @@ -22,13 +51,13 @@ public: virtual ~CheckableMessageBox(); static QDialogButtonBox::StandardButton - question(QWidget *parent, - const QString &title, - const QString &question, - const QString &checkBoxText, - bool *checkBoxSetting, - QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No, - QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No); + question(QWidget *parent, + const QString &title, + const QString &question, + const QString &checkBoxText, + bool *checkBoxSetting, + QDialogButtonBox::StandardButtons buttons = QDialogButtonBox::Yes|QDialogButtonBox::No, + QDialogButtonBox::StandardButton defaultButton = QDialogButtonBox::No); QString text() const; void setText(const QString &); From 63a13cf9cac94f8b642d61b2c9c11f193c8098ad Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Wed, 20 Feb 2013 19:29:12 +0100 Subject: [PATCH 692/916] Whoops, removed an include --- apps/launcher/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 5d57dce55..a5c6e30a5 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,4 +1,5 @@ #include +#include #include "maindialog.hpp" From 7fcca180b6751249ae61c13660659501af5317cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 20 Feb 2013 20:08:04 -0800 Subject: [PATCH 693/916] Implement rudimentary jumping --- apps/openmw/mwmechanics/character.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 713f1bb3b..6c8d558a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -181,10 +181,17 @@ Ogre::Vector3 CharacterController::update(float duration) const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + bool onground = world->isOnGround(mPtr); bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); + // This jump is all kinds of wrong. The speed is incorrect, the state should be set to + // Jump, and X/Y movement should be disallowed except for the initial thrust (which would + // be carried by "physics" until landing). + if(onground) + movement.z += vec.z * (500.0f*duration); + if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { if(vec.x > 0.0f) From ccf5c04706100de9a163b75ec1a4612f5cfcb29c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Feb 2013 12:10:56 +0100 Subject: [PATCH 694/916] updated credits files --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 936f3efd9..5c966d86b 100644 --- a/credits.txt +++ b/credits.txt @@ -16,6 +16,7 @@ Alexander Olofsson (Ace) Artem Kotsynyak (greye) athile BrotherBrick +Chris Robinson Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) Douglas Diniz (Dgdiniz) From 56468eaecf475a14c60c8975149281e656878b3b Mon Sep 17 00:00:00 2001 From: hasufell Date: Thu, 21 Feb 2013 19:19:53 +0100 Subject: [PATCH 695/916] Add install rule for opencs --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfd1c7dd3..0ef85e34d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -660,6 +660,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) # Install icon and .desktop INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}") From 9b7957cf20c12c82c62c4dc7575376dd363d4c83 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Feb 2013 19:27:07 +0100 Subject: [PATCH 696/916] fixed a missing inlcude --- components/bsa/bsa_file.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 5e529e18e..8db4fa888 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -23,9 +23,7 @@ #include "bsa_file.hpp" -//#include -//#include -//#include +#include #include "../files/constrainedfiledatastream.hpp" From 82595e66b2eec8f02557d8d01162327ddaa2ef86 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 21 Feb 2013 22:47:18 +0400 Subject: [PATCH 697/916] another missing header for #576 --- components/nif/nif_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index e6d3182ed..58d1bc9b8 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -37,7 +37,7 @@ //TODO: when threading is needed, enable these //#include -//#include +#include namespace Nif { From 71e5369f0457f4313be33c055886334f4ca59a07 Mon Sep 17 00:00:00 2001 From: lazydev Date: Fri, 22 Feb 2013 02:18:54 +0400 Subject: [PATCH 698/916] Loading translation data for all the plugin files, not only for the first one --- apps/openmw/engine.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index cb9396863..48206ba23 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -215,7 +215,7 @@ void OMW::Engine::addMaster (const std::string& master) { mMaster.push_back(master); std::string &str = mMaster.back(); - + // Append .esm if not already there std::string::size_type sep = str.find_last_of ("."); if (sep == std::string::npos) @@ -303,7 +303,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) } mOgre = new OEngine::Render::OgreRenderer; - + mOgre->configure( mCfgMgr.getLogPath().string(), renderSystem, @@ -345,7 +345,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) //Load translation data mTranslationDataStorage.setEncoder(mEncoder); - mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[0]); + for (size_t i = 0; i < mMaster.size(); i++) + mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[i]); // Create window manager - this manages all the MW-specific GUI windows MWScript::registerExtensions (mExtensions); From 9c3af5f344497ebdacc2477565a1df78a3996f29 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:26:30 -0800 Subject: [PATCH 699/916] Do not interpret noclip mode as flying --- apps/openmw/mwworld/worldimp.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e75bd1677..bfc313caa 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1389,15 +1389,9 @@ namespace MWWorld bool World::isFlying(const MWWorld::Ptr &ptr) const { - RefData &refdata = ptr.getRefData(); - const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(!physactor || !physactor->getCollisionMode()) - return true; - const MWWorld::Class &cls = MWWorld::Class::get(ptr); if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) return true; - return false; } From 7ec73c29f2ff1af05df4f3aac9f86907a805fbf2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:27:26 -0800 Subject: [PATCH 700/916] Do not return the player's Animation object for non-players --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1551f73b8..0b9730dea 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -923,7 +923,8 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors.getAnimation(ptr); - if(!anim) anim = mPlayer->getAnimation(); + if(!anim && ptr.getRefData().getHandle() == "player") + anim = mPlayer->getAnimation(); return anim; } From 84227caa0c715922b8f3984beed92b141de23fd8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 01:30:06 -0800 Subject: [PATCH 701/916] Cleanup Npc::getSpeed a little --- apps/openmw/mwclass/npc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4a31334ad..642c7f645 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -335,14 +335,16 @@ namespace MWClass float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() * fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat()); + if(npcdata->mNpcStats.isWerewolf()) + runSpeed *= fWereWolfRunMult->getFloat(); float moveSpeed; if(normalizedEncumbrance >= 1.0f) moveSpeed = 0.0f; - else if(world->isFlying(ptr)) + else if(mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) { float flySpeed = 0.01f*(npcdata->mCreatureStats.getAttribute(ESM::Attribute::Speed).getModified() + - mageffects.get(MWMechanics::EffectKey(10)).mMagnitude/*levitate*/); + mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude); flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed = std::max(0.0f, flySpeed); @@ -353,7 +355,7 @@ namespace MWClass float swimSpeed = walkSpeed; if(Npc::getStance(ptr, Run, false)) swimSpeed = runSpeed; - swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1)).mMagnitude/*swift swim*/; + swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1/*swift swim*/)).mMagnitude; swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; @@ -365,8 +367,6 @@ namespace MWClass if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) moveSpeed *= 0.75f; - if(npcdata->mNpcStats.isWerewolf() && Npc::getStance(ptr, Run, false)) - moveSpeed *= fWereWolfRunMult->getFloat(); return moveSpeed; } From 5e1ec9e128599ee95664799f871122e9db745eff Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 22 Feb 2013 08:27:00 -0800 Subject: [PATCH 702/916] improved book window layout --- files/mygui/openmw_book.layout | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/files/mygui/openmw_book.layout b/files/mygui/openmw_book.layout index 894c1dbeb..96d1153f0 100644 --- a/files/mygui/openmw_book.layout +++ b/files/mygui/openmw_book.layout @@ -2,41 +2,45 @@ - + - + + - + + - + - + + - + - + + - + - + - - + + From 9dee2a72cd732bc302074f9ecf7e317704da3704 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 09:22:06 -0800 Subject: [PATCH 703/916] Use a separate method to calculate animation velocity --- apps/openmw/mwrender/animation.cpp | 85 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f4b618866..707aedcd9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -175,6 +175,49 @@ void Animation::setLooping(bool loop) } +void Animation::calcAnimVelocity() +{ + const Ogre::NodeAnimationTrack *track = 0; + + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(!track && trackiter.hasMoreElements()) + { + const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); + if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + track = cur; + } + + if(track && track->getNumKeyFrames() > 1) + { + float loopstarttime = 0.0f; + float loopstoptime = mCurrentAnim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); + while(keyiter != mCurrentKeys->end()) + { + if(keyiter->second == "loop start") + loopstarttime = keyiter->first; + else if(keyiter->second == "loop stop") + { + loopstoptime = keyiter->first; + break; + } + keyiter++; + } + + if(loopstoptime > loopstarttime) + { + Ogre::TransformKeyFrame startkf(0, loopstarttime); + Ogre::TransformKeyFrame endkf(0, loopstoptime); + + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + + mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); + } + } +} + void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) { Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); @@ -305,47 +348,7 @@ void Animation::play(const std::string &groupname, const std::string &start, boo mAnimVelocity = 0.0f; if(mNonAccumRoot) - { - const Ogre::NodeAnimationTrack *track = 0; - - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - track = cur; - } - - if(track && track->getNumKeyFrames() > 1) - { - float loopstarttime = 0.0f; - float loopstoptime = mCurrentAnim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); - while(keyiter != mCurrentKeys->end()) - { - if(keyiter->second == "loop start") - loopstarttime = keyiter->first; - else if(keyiter->second == "loop stop") - { - loopstoptime = keyiter->first; - break; - } - keyiter++; - } - - if(loopstoptime > loopstarttime) - { - Ogre::TransformKeyFrame startkf(0, loopstarttime); - Ogre::TransformKeyFrame endkf(0, loopstoptime); - - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); - - mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); - } - } - } + calcAnimVelocity(); found = true; break; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2f930e9ad..c6e230670 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -39,6 +39,8 @@ protected: float mAnimVelocity; float mAnimSpeedMult; + void calcAnimVelocity(); + /* Applies the given animation to the given skeleton instance, using the specified time. */ void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); From ecbf1568a1c1a1e37507b5fdd8acdfe7f38ea784 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 22 Feb 2013 10:15:29 -0800 Subject: [PATCH 704/916] Fix NPC part attachment --- apps/openmw/mwrender/npcanimation.cpp | 29 ++++++++++++++++----------- apps/openmw/mwrender/npcanimation.hpp | 5 +++-- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 120996a70..4d8119c72 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -133,10 +133,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor if(mNpc->mModel.length() > 0) insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - updateParts(); + updateParts(true); } -void NpcAnimation::updateParts() +void NpcAnimation::updateParts(bool forceupdate) { static const struct { int numRemoveParts; // Max: 1 @@ -212,11 +212,21 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + for(size_t i = 0;!forceupdate && i < slotlistsize;i++) + { + MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); + if(this->*slotlist[i].part != iter) + { + forceupdate = true; + break; + } + } + if(!forceupdate) + return; + for(size_t i = 0;i < slotlistsize;i++) { MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); - if(this->*slotlist[i].part == iter) - continue; this->*slotlist[i].part = iter; removePartGroup(slotlist[i].slot); @@ -332,12 +342,12 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) { - if(mTimeToChange > .2) + if(mTimeToChange <= 0.0f) { - mTimeToChange = 0; + mTimeToChange = 0.2f; updateParts(); } - mTimeToChange += timepassed; + mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); @@ -441,9 +451,4 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector Date: Fri, 22 Feb 2013 11:16:00 -0800 Subject: [PATCH 705/916] Fix character preview --- apps/openmw/mwrender/characterpreview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 24df30556..9f8962d7c 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -121,8 +121,8 @@ namespace MWRender void InventoryPreview::update(int sizeX, int sizeY) { - mAnimation->runAnimation(0.0f); mAnimation->forceUpdate(); + mAnimation->runAnimation(0.0f); mViewport->setDimensions (0, 0, std::min(1.f, float(sizeX) / float(512)), std::min(1.f, float(sizeY) / float(1024))); From f17ea109ca653a92da910141640a48ff440cb44f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 04:06:05 +0100 Subject: [PATCH 706/916] Fix light positions --- apps/openmw/mwclass/light.cpp | 9 +------- apps/openmw/mwrender/objects.cpp | 39 ++++++++++++++++++++++++++++---- apps/openmw/mwrender/objects.hpp | 4 ++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 235e57d37..094ae5b16 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -36,14 +36,7 @@ namespace MWClass objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); if (!model.empty()) - objects.insertMesh(ptr, "meshes\\" + model); - - const int color = ref->mBase->mData.mColor; - const float r = ((color >> 0) & 0xFF) / 255.0f; - const float g = ((color >> 8) & 0xFF) / 255.0f; - const float b = ((color >> 16) & 0xFF) / 255.0f; - const float radius = float (ref->mBase->mData.mRadius); - objects.insertLight (ptr, r, g, b, radius); + objects.insertMesh(ptr, "meshes\\" + model, true); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index bd5f95c24..c51cafc0e 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -34,6 +34,18 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) for (int i=node->numAttachedObjects()-1; i>=0; --i) { Ogre::MovableObject *object = node->getAttachedObject (i); + + // for entities, destroy any objects attached to bones + if (object->getTypeFlags () == Ogre::SceneManager::ENTITY_TYPE_MASK) + { + Ogre::Entity* ent = static_cast(object); + Ogre::Entity::ChildObjectListIterator children = ent->getAttachedObjectIterator (); + while (children.hasMoreElements()) + { + mRenderer.getScene ()->destroyMovableObject (children.getNext ()); + } + } + node->detachObject (object); mRenderer.getScene()->destroyMovableObject (object); } @@ -87,7 +99,7 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) mIsStatic = static_; } -void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) +void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light) { Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); assert(insert); @@ -204,17 +216,29 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) iter++; } } + + if (light) + { + insertLight(ptr, entities.mSkelBase); + } } -void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius) +void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) { Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle()); assert(insert); - Ogre::Light *light = mRenderer.getScene()->createLight(); - light->setDiffuseColour (r, g, b); MWWorld::LiveCellRef *ref = ptr.get(); + const int color = ref->mBase->mData.mColor; + const float r = ((color >> 0) & 0xFF) / 255.0f; + const float g = ((color >> 8) & 0xFF) / 255.0f; + const float b = ((color >> 16) & 0xFF) / 255.0f; + const float radius = float (ref->mBase->mData.mRadius); + + Ogre::Light *light = mRenderer.getScene()->createLight(); + light->setDiffuseColour (r, g, b); + LightInfo info; info.name = light->getName(); info.radius = radius; @@ -265,7 +289,12 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f light->setAttenuation(r*10, 0, 0, attenuation); } - insert->attachObject(light); + // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node + if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight")) + skelBase->attachObjectToBone ("AttachLight", light); + else + insert->attachObject(light); + mLights.push_back(info); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index b2bdac683..283c05388 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -73,8 +73,8 @@ public: Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); - void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); - void insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, float radius); + void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase); void enableLights(); void disableLights(); From 5b099393faa2c3cfe4cd4df051f93b452b8a36c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 04:43:51 +0100 Subject: [PATCH 707/916] Fix time factor --- apps/openmw/mwrender/refraction.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 67fe9e340..64234cc57 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -33,7 +33,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.0078, 0.0576, 0.150)); + vp->setBackgroundColour (Ogre::ColourValue(0.180, 0.235, 0.22352)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c4f2d99cb..5baa8e7cc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -349,9 +349,10 @@ void RenderingManager::update (float duration, bool paused) mRendering.update(duration); + Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); + if(paused) { - Ogre::ControllerManager::getSingleton().setTimeFactor(0.f); return; } @@ -520,8 +521,8 @@ void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) configureFog(mCell.mCell->mAmbi.mFogDensity, color); - if (mWater) - mWater->setViewportBackground (Ogre::ColourValue(0.8f, 0.9f, 1.0f)); + //if (mWater) + // mWater->setViewportBackground (Ogre::ColourValue(0.8f, 0.9f, 1.0f)); } void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) From 6f89d453a5213a04eab4c168d495ea71e838a082 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Fri, 22 Feb 2013 21:53:32 -0600 Subject: [PATCH 708/916] Operations widget height fix and abort button feature. Successfully tested resizing of Operations QDockWidget for multiple concurrent operations. --- apps/opencs/model/doc/document.cpp | 3 +- apps/opencs/view/doc/operation.cpp | 55 ++++++++++++++++++++++------ apps/opencs/view/doc/operation.hpp | 24 ++++++++++-- apps/opencs/view/doc/operations.cpp | 34 +++++++++++++---- apps/opencs/view/doc/operations.hpp | 6 ++- apps/opencs/view/doc/subview.cpp | 1 - apps/opencs/view/doc/view.cpp | 29 ++++++++++++--- apps/opencs/view/doc/view.hpp | 10 ++++- apps/opencs/view/doc/viewmanager.cpp | 6 ++- 9 files changed, 132 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index da29f6c68..d63aaeccb 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -249,6 +249,7 @@ void CSMDoc::Document::abortOperation (int type) if (type==State_Saving) { + mSaveCount=0; mSaveTimer.stop(); emit stateChanged (getState(), this); } @@ -297,4 +298,4 @@ CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId& void CSMDoc::Document::progress (int current, int max, int type) { emit progress (current, max, type, 1, this); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/operation.cpp b/apps/opencs/view/doc/operation.cpp index c301195bc..6977d7953 100644 --- a/apps/opencs/view/doc/operation.cpp +++ b/apps/opencs/view/doc/operation.cpp @@ -1,8 +1,11 @@ - #include "operation.hpp" #include +#include +#include +#include + #include "../../model/doc/document.hpp" void CSVDoc::Operation::updateLabel (int threads) @@ -28,24 +31,44 @@ void CSVDoc::Operation::updateLabel (int threads) stream << name << " (%p%)"; } - setFormat (stream.str().c_str()); + mProgressBar->setFormat (stream.str().c_str()); } } -CSVDoc::Operation::Operation (int type) : mType (type), mStalling (false) +CSVDoc::Operation::Operation (int type, QWidget* parent) : mType (type), mStalling (false) { /// \todo Add a cancel button or a pop up menu with a cancel item + initWidgets(); setBarColor( type); updateLabel(); /// \todo assign different progress bar colours to allow the user to distinguish easily between operation types } +CSVDoc::Operation::~Operation() +{ + delete mLayout; + delete mProgressBar; + delete mAbortButton; +} + +void CSVDoc::Operation::initWidgets() +{ + mProgressBar = new QProgressBar (); + mAbortButton = new QPushButton("Abort"); + mLayout = new QHBoxLayout(); + + mLayout->addWidget (mProgressBar); + mLayout->addWidget (mAbortButton); + + connect (mAbortButton, SIGNAL (clicked()), this, SLOT (abortOperation())); +} + void CSVDoc::Operation::setProgress (int current, int max, int threads) { updateLabel (threads); - setRange (0, max); - setValue (current); + mProgressBar->setRange (0, max); + mProgressBar->setValue (current); } int CSVDoc::Operation::getType() const @@ -64,8 +87,6 @@ void CSVDoc::Operation::setBarColor (int type) "margin: 2px 1px 1p 2px;" "}"; - // "QProgressBar::chunk {background-color: %1;}"; - QString topColor = "#F2F6F8"; QString bottomColor = "#E0EFF9"; QString midTopColor = "#D8E1E7"; @@ -82,7 +103,7 @@ void CSVDoc::Operation::setBarColor (int type) midTopColor = "#F17432"; midBottomColor = "#EA5507"; bottomColor = "#FB955E"; // red gloss #2 - //break; + break; case CSMDoc::State_Searching: @@ -90,7 +111,7 @@ void CSVDoc::Operation::setBarColor (int type) midTopColor = "#ABD3EE"; midBottomColor = "#89C3EB"; bottomColor = "#D5EBFB"; //blue gloss #4 - //break; + break; case CSMDoc::State_Verifying: @@ -98,7 +119,7 @@ void CSVDoc::Operation::setBarColor (int type) midTopColor = "#8EB92A"; midBottomColor = "#72AA00"; bottomColor = "#9ECB2D"; //green gloss - //break; + break; case CSMDoc::State_Compiling: @@ -106,7 +127,7 @@ void CSVDoc::Operation::setBarColor (int type) midTopColor = "#C19E67"; midBottomColor = "#B68D4C"; bottomColor = "#E9D4B3"; //l Brown 3D - //break; + break; default: @@ -116,5 +137,15 @@ void CSVDoc::Operation::setBarColor (int type) midBottomColor = "#B5C6D0"; // gray gloss for undefined ops } - setStyleSheet(style.arg(topColor).arg(midTopColor).arg(midBottomColor).arg(bottomColor)); + mProgressBar->setStyleSheet(style.arg(topColor).arg(midTopColor).arg(midBottomColor).arg(bottomColor)); +} + +QHBoxLayout *CSVDoc::Operation::getLayout() const +{ + return mLayout; +} + +void CSVDoc::Operation::abortOperation() +{ + emit abortOperation (mType); } diff --git a/apps/opencs/view/doc/operation.hpp b/apps/opencs/view/doc/operation.hpp index a5abf73b7..48839fada 100644 --- a/apps/opencs/view/doc/operation.hpp +++ b/apps/opencs/view/doc/operation.hpp @@ -1,16 +1,23 @@ #ifndef CSV_DOC_OPERATION_H #define CSV_DOC_OPERATION_H -#include +#include + +class QHBoxLayout; +class QPushButton; +class QProgressBar; namespace CSVDoc { - class Operation : public QProgressBar + class Operation : public QObject { Q_OBJECT int mType; bool mStalling; + QProgressBar *mProgressBar; + QPushButton *mAbortButton; + QHBoxLayout *mLayout; // not implemented Operation (const Operation&); @@ -20,15 +27,26 @@ namespace CSVDoc public: - Operation (int type); + Operation (int type, QWidget *parent); + ~Operation(); void setProgress (int current, int max, int threads); int getType() const; + QHBoxLayout *getLayout() const; private: void setBarColor (int type); + void initWidgets(); + + signals: + + void abortOperation (int type); + + private slots: + + void abortOperation(); }; } diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index ba444a119..71cacbe17 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -1,7 +1,7 @@ - #include "operations.hpp" #include +#include #include "operation.hpp" @@ -11,12 +11,14 @@ CSVDoc::Operations::Operations() setFeatures (QDockWidget::NoDockWidgetFeatures); - QWidget *widget = new QWidget; - setWidget (widget); - + QWidget *widgetContainer = new QWidget (this); mLayout = new QVBoxLayout; - widget->setLayout (mLayout); + widgetContainer->setLayout (mLayout); + setWidget (widgetContainer); + + setFixedHeight (widgetContainer->height()); + setTitleBarWidget (new QWidget (this)); } void CSVDoc::Operations::setProgress (int current, int max, int type, int threads) @@ -28,11 +30,18 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread return; } - Operation *operation = new Operation (type); + int oldCount = mOperations.size(); + int newCount = oldCount + 1; - mLayout->addWidget (operation); + Operation *operation = new Operation (type, this); + connect (operation, SIGNAL (abortOperation (int)), this, SIGNAL (abortOperation (int))); + + mLayout->addLayout (operation->getLayout()); mOperations.push_back (operation); operation->setProgress (current, max, threads); + + if ( oldCount > 0) + setFixedHeight (height()/oldCount * newCount); } void CSVDoc::Operations::quitOperation (int type) @@ -40,8 +49,17 @@ void CSVDoc::Operations::quitOperation (int type) for (std::vector::iterator iter (mOperations.begin()); iter!=mOperations.end(); ++iter) if ((*iter)->getType()==type) { + int oldCount = mOperations.size(); + int newCount = oldCount - 1; + + mLayout->removeItem ((*iter)->getLayout()); + delete *iter; mOperations.erase (iter); + + if (oldCount > 1) + setFixedHeight (height() / oldCount * newCount); + break; } -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/operations.hpp b/apps/opencs/view/doc/operations.hpp index b96677450..71c595f66 100644 --- a/apps/opencs/view/doc/operations.hpp +++ b/apps/opencs/view/doc/operations.hpp @@ -31,7 +31,11 @@ namespace CSVDoc void quitOperation (int type); ///< Calling this function for an operation that is not running is a no-op. + + signals: + + void abortOperation (int type); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index 1c356fa73..affada012 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -1,4 +1,3 @@ - #include "subview.hpp" CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 4fd03041f..6aafef4ed 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -1,4 +1,3 @@ - #include "view.hpp" #include @@ -7,6 +6,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" @@ -117,13 +117,16 @@ void CSVDoc::View::updateActions() mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); } -CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) -: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent) + : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), QMainWindow (viewParent) { setDockOptions (QMainWindow::AllowNestedDocks); resize (300, 300); /// \todo get default size from settings and set reasonable minimal size + mSubViewWindow = new QMainWindow(); + setCentralWidget (mSubViewWindow); + mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); @@ -133,6 +136,8 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to CSVWorld::addSubViewFactories (mSubViewFactory); CSVTools::addSubViewFactories (mSubViewFactory); + + connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); } CSVDoc::View::~View() @@ -171,7 +176,7 @@ void CSVDoc::View::updateDocumentState() for (int i=0; operations[i]!=-1; ++i) if (!(state & operations[i])) - mOperations->quitOperation (operations[i]); + mOperations->quitOperation (operations[i]); QList subViews = findChildren(); @@ -195,7 +200,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) SubView *view = mSubViewFactory.makeSubView (id, *mDocument); - addDockWidget (Qt::TopDockWidgetArea, view); + mSubViewWindow->addDockWidget (Qt::TopDockWidgetArea, view); connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, SLOT (addSubView (const CSMWorld::UniversalId&))); @@ -226,4 +231,16 @@ void CSVDoc::View::addGlobalsSubView() void CSVDoc::View::addGmstsSubView() { addSubView (CSMWorld::UniversalId::Type_Gmsts); -} \ No newline at end of file +} + +void CSVDoc::View::abortOperation (int type) +{ + mDocument->abortOperation (type); + mOperations->quitOperation (type); + updateActions(); +} + +QDockWidget *CSVDoc::View::getOperations() const +{ + return mOperations; +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 6bdd54e6b..28ab24b74 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -9,6 +9,7 @@ #include "subviewfactory.hpp" class QAction; +class QDockWidget; namespace CSMDoc { @@ -40,6 +41,7 @@ namespace CSVDoc std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; + QMainWindow* mSubViewWindow; // not implemented View (const View&); @@ -65,7 +67,7 @@ namespace CSVDoc public: - View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); + View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent); ///< The ownership of \a document is not transferred to *this. virtual ~View(); @@ -80,6 +82,8 @@ namespace CSVDoc void updateProgress (int current, int max, int type, int threads); + QDockWidget *getOperations() const; + signals: void newDocumentRequest(); @@ -101,7 +105,9 @@ namespace CSVDoc void addGlobalsSubView(); void addGmstsSubView(); + + void abortOperation (int type); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 473049999..a8faefb97 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -59,7 +59,9 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); } - View *view = new View (*this, document, countViews (document)+1); + QMainWindow *mainWindow = new QMainWindow; + + View *view = new View (*this, document, countViews (document)+1, mainWindow); mViews.push_back (view); @@ -119,4 +121,4 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) (*iter)->updateProgress (current, max, type, threads); -} \ No newline at end of file +} From 01102f9c73b9e28e1fc23928f5123cd2409831f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 05:53:20 +0100 Subject: [PATCH 709/916] Don't emit if there wasn't enough movement --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/ripplesimulation.cpp | 13 +++++++++++-- apps/openmw/mwrender/ripplesimulation.hpp | 4 +++- apps/openmw/mwrender/water.cpp | 6 ++++++ apps/openmw/mwrender/water.hpp | 2 ++ files/materials/watersim_heightmap.shader | 2 +- 6 files changed, 24 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5baa8e7cc..c9f7603be 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -376,7 +376,7 @@ void RenderingManager::update (float duration, bool paused) float *fpos = data.getPosition().pos; // only for LocalMap::updatePlayer() - Ogre::Vector3 pos(fpos[0], -fpos[2], -fpos[1]); + Ogre::Vector3 pos(fpos[0], fpos[2], -fpos[1]); Ogre::SceneNode *node = data.getBaseNode(); Ogre::Quaternion orient = diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 249397005..6c9264b60 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -21,7 +21,8 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) mRippleAreaLength(1000), mImpulseSize(20), mTexelOffset(0,0), - mFirstUpdate(true) + mFirstUpdate(true), + mLastPos(0,0) { Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); @@ -141,8 +142,16 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); } -void RippleSimulation::addImpulse(Ogre::Vector2 position) +void RippleSimulation::addImpulse(Ogre::Vector2 position, float scale, float force) { + // don't emit if there wasn't enough movement + /// \todo this should be done somewhere else, otherwise multiple emitters cannot be supported + if ((position - mLastPos).length () <= 2) + return; + + mLastPos = position; + + /// \todo scale, force mImpulses.push(position); } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index c792a3214..2f8cae24f 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -24,7 +24,7 @@ public: void update(float dt, Ogre::Vector2 position); - void addImpulse (Ogre::Vector2 position); + void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); private: Ogre::RenderTexture* mRenderTargets[4]; @@ -34,6 +34,8 @@ private: float mRippleAreaLength; float mImpulseSize; + Ogre::Vector2 mLastPos; + bool mFirstUpdate; Ogre::Camera* mCamera; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f0680f208..33b6733ba 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -499,4 +499,10 @@ void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& co } } +void Water::addImpulse (Vector2 position, float scale, float force) +{ + if (mSimulation) + mSimulation->addImpulse (position, scale, force); +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 6100b7cfd..eb7d98f5d 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -146,6 +146,8 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); + void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); + void setViewportBackground(const Ogre::ColourValue& bg); void processChangedSettings(const Settings::CategorySettingVector& settings); diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader index e19270d39..50d375efe 100644 --- a/files/materials/watersim_heightmap.shader +++ b/files/materials/watersim_heightmap.shader @@ -1,6 +1,6 @@ #include "core.h" -#define DAMPING 0.92 +#define DAMPING 0.95 #include "watersim_common.h" From 7046e7ae3def07d41d314bbbdb034c45a3e12f64 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 09:02:05 +0100 Subject: [PATCH 710/916] Water fog fix --- files/materials/water.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/water.shader b/files/materials/water.shader index ac6b81240..09788d45b 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -295,7 +295,7 @@ } else { - float fogValue = shSaturate((length(cameraPos.xyz-position.xyz) - fogParams.y) * fogParams.w); + float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); } From 7e816c826bf6c642fee570c099aa29485b0b3ecb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Feb 2013 09:17:12 +0100 Subject: [PATCH 711/916] Fix lights without a mesh --- apps/openmw/mwclass/light.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 094ae5b16..9d0fe298b 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -37,6 +37,8 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); + else + objects.insertLight(ptr, NULL); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const From f841576bba22b7e8b0f2b2ddb61878b64c0c33db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 01:54:46 -0800 Subject: [PATCH 712/916] Don't override animations played with playgroup --- apps/openmw/mwmechanics/character.cpp | 4 ++-- apps/openmw/mwmechanics/character.hpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6c8d558a4..7b166ba91 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -218,7 +218,7 @@ Ogre::Vector3 CharacterController::update(float duration) // Apply any sideways movement manually movement.x += vec.x * (speed*duration); } - else + else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : CharState_Idle), true); } @@ -246,7 +246,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int while(count-- > 0) mAnimQueue.push_back(groupname); mCurrentGroup = groupname; - mState = CharState_Idle; + mState = CharState_SpecialIdle; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); } else if(mode == 0) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 996687a3e..2465aea98 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -14,6 +14,7 @@ namespace MWMechanics { enum CharacterState { + CharState_SpecialIdle, CharState_Idle, CharState_Idle2, CharState_Idle3, From c9ca565462b599356e1681bb769218eeda3da411 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:05:09 +0100 Subject: [PATCH 713/916] removed a redundant function call --- apps/opencs/view/doc/view.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 6aafef4ed..286d7a6ed 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -236,7 +236,6 @@ void CSVDoc::View::addGmstsSubView() void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); - mOperations->quitOperation (type); updateActions(); } From b8f5813609f0c32705d95f83106e2c5005fee19e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 03:34:03 -0800 Subject: [PATCH 714/916] Set all animation sources at once --- apps/openmw/mwrender/activatoranimation.cpp | 1 + apps/openmw/mwrender/animation.cpp | 100 +++++++++----------- apps/openmw/mwrender/animation.hpp | 12 ++- apps/openmw/mwrender/creatureanimation.cpp | 11 ++- apps/openmw/mwrender/npcanimation.cpp | 9 +- 5 files changed, 70 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index f951307b6..7bc89b917 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -51,6 +51,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) ent->setVisibilityFlags(RV_Misc); ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + setAnimationSource(mesh); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 707aedcd9..160641eb0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,45 +46,64 @@ Animation::~Animation() } -Ogre::Bone *Animation::insertSkeletonSource(const std::string &name) +void Animation::setAnimationSources(const std::vector &names) { Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - Ogre::SkeletonPtr skel = skelMgr.getByName(name); - if(skel.isNull()) + + mCurrentAnim = NULL; + mCurrentKeys = NULL; + mAnimVelocity = 0.0f; + mAccumRoot = NULL; + mNonAccumRoot = NULL; + mSkeletonSources.clear(); + + std::vector::const_iterator nameiter = names.begin(); + while(nameiter != names.end()) { - NifOgre::Loader::createSkeleton(name); - skel = skelMgr.getByName(name); + Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); if(skel.isNull()) { - std::cerr<< "Failed to get skeleton source "<touch(); - mSkeletonSources.push_back(skel); + skel->touch(); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); - while(boneiter.hasMoreElements()) - { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; - - for(int i = 0;i < skel->getNumAnimations();i++) + Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + while(boneiter.hasMoreElements()) { - Ogre::Animation *anim = skel->getAnimation(i); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); - if(!groupdata.isEmpty()) - mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + Ogre::Bone *bone = boneiter.getNext(); + Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); + const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); + if(data.isEmpty() || !Ogre::any_cast(data)) + continue; + + if(!mNonAccumRoot && mEntityList.mSkelBase) + { + mAccumRoot = mInsert; + mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); + } + + mSkeletonSources.push_back(skel); + for(int i = 0;i < skel->getNumAnimations();i++) + { + Ogre::Animation *anim = skel->getAnimation(i); + const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ + "@"+anim->getName()); + if(!groupdata.isEmpty()) + mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); + } + + break; } - return bone; + nameiter++; } - - return NULL; } void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) @@ -111,31 +130,6 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); - - Ogre::Bone *bone = insertSkeletonSource(skelinst->getName()); - if(!bone) - { - for(std::vector::const_iterator iter(mSkeletonSources.begin()); - !bone && iter != mSkeletonSources.end();iter++) - { - Ogre::Skeleton::BoneIterator boneiter = (*iter)->getBoneIterator(); - while(boneiter.hasMoreElements()) - { - bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(!data.isEmpty() && Ogre::any_cast(data)) - break; - - bone = NULL; - } - } - } - if(bone) - { - mAccumRoot = mInsert; - mNonAccumRoot = skelinst->getBone(bone->getName()); - } } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index c6e230670..130805a50 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -57,9 +57,15 @@ protected: * anything. If the marker is not found, it resets to the beginning. */ void reset(const std::string &marker); - /* Inserts an additional skeleton into the animation source chain. Returns - * the bone representing the non-accum root from the base skeleton. */ - Ogre::Bone *insertSkeletonSource(const std::string &name); + /* Specifies a list of skeleton names to use as animation sources. */ + void setAnimationSources(const std::vector &names); + + /* Specifies a single skeleton name to use as an animation source. */ + void setAnimationSource(const std::string &name) + { + std::vector names(1, name); + setAnimationSources(names); + } void createEntityList(Ogre::SceneNode *node, const std::string &model); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 094281c46..b85c4dbbd 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -23,10 +23,9 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - if((ref->mBase->mFlags&ESM::Creature::Biped)) - insertSkeletonSource("meshes\\base_anim.nif"); + std::string model = "meshes\\"+ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), "meshes\\"+ref->mBase->mModel); + createEntityList(mPtr.getRefData().getBaseNode(), model); for(size_t i = 0;i < mEntityList.mEntities.size();i++) { Ogre::Entity *ent = mEntityList.mEntities[i]; @@ -52,6 +51,12 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) } ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + + std::vector names; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + names.push_back("meshes\\base_anim.nif"); + names.push_back(model); + setAnimationSources(names); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 4d8119c72..3f135b7f6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -125,13 +125,14 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } + std::vector skelnames(1, smodel); if(!mNpc->isMale() && !isBeast) - insertSkeletonSource("meshes\\base_anim_female.nif"); + skelnames.push_back("meshes\\base_anim_female.nif"); else if(mBodyPrefix.find("argonian") != std::string::npos) - insertSkeletonSource("meshes\\argonian_swimkna.nif"); - + skelnames.push_back("meshes\\argonian_swimkna.nif"); if(mNpc->mModel.length() > 0) - insertSkeletonSource("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + setAnimationSources(skelnames); updateParts(true); } From 6f5a772d02d886d3777de0b25f45db878f636aad Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:35:05 +0100 Subject: [PATCH 715/916] fixed another case handling problem --- apps/opencs/model/world/idcollection.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 5a1d21ae4..9b69dfb88 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -171,7 +171,7 @@ namespace CSMWorld record2.mModified = record; mRecords.push_back (record2); - mIndex.insert (std::make_pair (id, mRecords.size()-1)); + mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), mRecords.size()-1)); } else { @@ -306,7 +306,7 @@ namespace CSMWorld void IdCollection::appendRecord (const RecordBase& record) { mRecords.push_back (dynamic_cast&> (record)); - mIndex.insert (std::make_pair (getId (record), mRecords.size()-1)); + mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (getId (record)), mRecords.size()-1)); } template From 868916a9a22d0dd9f8713b6ea57206d6ee689d52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 12:51:45 +0100 Subject: [PATCH 716/916] added add-on global variables in the same way add-on GMSTs were added --- apps/opencs/model/doc/document.cpp | 32 ++++++++++++++++++++++++++++++ apps/opencs/model/doc/document.hpp | 5 +++++ 2 files changed, 37 insertions(+) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index d63aaeccb..b361577be 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -20,6 +20,7 @@ void CSMDoc::Document::load (const std::vector::const_i getData().loadFile (*end2, false); addOptionalGmsts(); + addOptionalGlobals(); } void CSMDoc::Document::addOptionalGmsts() @@ -139,6 +140,26 @@ void CSMDoc::Document::addOptionalGmsts() } } +void CSMDoc::Document::addOptionalGlobals() +{ + static const char *sGlobals[] = + { + "dayspassed", + "pcwerewolf", + "pcyear", + 0 + }; + + for (int i=0; sGlobals[i]; ++i) + { + ESM::Global global; + global.mId = sGlobals[i]; + global.mType = ESM::VT_Int; + global.mValue = 0; + addOptionalGlobal (global); + } +} + void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) { if (getData().getGmsts().searchId (gmst.mId)==-1) @@ -150,6 +171,17 @@ void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) } } +void CSMDoc::Document::addOptionalGlobal (const ESM::Global& global) +{ + if (getData().getGlobals().searchId (global.mId)==-1) + { + CSMWorld::Record record; + record.mBase = global; + record.mState = CSMWorld::RecordBase::State_BaseOnly; + getData().getGlobals().appendRecord (record); + } +} + void CSMDoc::Document::createBase() { static const char *sGlobals[] = diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 413e840d3..a7b198689 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -20,6 +20,7 @@ class QAbstractItemModel; namespace ESM { struct GameSetting; + struct Global; } namespace CSMDoc @@ -53,8 +54,12 @@ namespace CSMDoc void addOptionalGmsts(); + void addOptionalGlobals(); + void addOptionalGmst (const ESM::GameSetting& gmst); + void addOptionalGlobal (const ESM::Global& global); + public: Document (const std::vector& files, bool new_); From 9659b4a95e1d4bb40560046b288173ec54f07ab2 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 21 Feb 2013 23:56:34 +0400 Subject: [PATCH 717/916] update NpcAnimation inventory reference on cell change --- apps/openmw/mwrender/actors.cpp | 4 ++- apps/openmw/mwrender/npcanimation.cpp | 52 +++++++++++++-------------- apps/openmw/mwrender/npcanimation.hpp | 8 ++++- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 92f5cbe28..e886f3a09 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -163,7 +163,9 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { /// \note Update key (Ptr's are compared only with refdata so mCell /// on key is outdated), maybe redundant - Animation *anim = iter->second; + NpcAnimation *anim = static_cast(iter->second); + anim->updateParts(MWWorld::Class::get(ptr).getInventoryStore(ptr)); + mAllActors.erase(iter); mAllActors[ptr] = anim; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d33bdda91..6f6c9e740 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -48,21 +48,21 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(), mStateID(-1), - mInv(inv), + mInv(&inv), mTimeToChange(0), mVisibilityFlags(visibilityFlags), - mRobe(mInv.end()), - mHelmet(mInv.end()), - mShirt(mInv.end()), - mCuirass(mInv.end()), - mGreaves(mInv.end()), - mPauldronL(mInv.end()), - mPauldronR(mInv.end()), - mBoots(mInv.end()), - mPants(mInv.end()), - mGloveL(mInv.end()), - mGloveR(mInv.end()), - mSkirtIter(mInv.end()) + mRobe(mInv->end()), + mHelmet(mInv->end()), + mShirt(mInv->end()), + mCuirass(mInv->end()), + mGreaves(mInv->end()), + mPauldronL(mInv->end()), + mPauldronR(mInv->end()), + mBoots(mInv->end()), + mPants(mInv->end()), + mGloveL(mInv->end()), + mGloveR(mInv->end()), + mSkirtIter(mInv->end()) { mNpc = ptr.get()->mBase; @@ -160,7 +160,7 @@ void NpcAnimation::updateParts() }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { - MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); if(*slotlist[i].iter != iter) { *slotlist[i].iter = iter; @@ -171,7 +171,7 @@ void NpcAnimation::updateParts() if(apparelChanged) { - if(mRobe != mInv.end()) + if(mRobe != mInv->end()) { MWWorld::Ptr ptr = *mRobe; @@ -191,7 +191,7 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); } - if(mSkirtIter != mInv.end()) + if(mSkirtIter != mInv->end()) { MWWorld::Ptr ptr = *mSkirtIter; @@ -203,39 +203,39 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); } - if(mHelmet != mInv.end()) + if(mHelmet != mInv->end()) { removeIndividualPart(ESM::PRT_Hair); const ESM::Armor *armor = (mHelmet->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); } - if(mCuirass != mInv.end()) + if(mCuirass != mInv->end()) { const ESM::Armor *armor = (mCuirass->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); } - if(mGreaves != mInv.end()) + if(mGreaves != mInv->end()) { const ESM::Armor *armor = (mGreaves->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); } - if(mPauldronL != mInv.end()) + if(mPauldronL != mInv->end()) { const ESM::Armor *armor = (mPauldronL->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); } - if(mPauldronR != mInv.end()) + if(mPauldronR != mInv->end()) { const ESM::Armor *armor = (mPauldronR->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); } - if(mBoots != mInv.end()) + if(mBoots != mInv->end()) { if(mBoots->getTypeName() == typeid(ESM::Clothing).name()) { @@ -250,7 +250,7 @@ void NpcAnimation::updateParts() addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); } } - if(mGloveL != mInv.end()) + if(mGloveL != mInv->end()) { if(mGloveL->getTypeName() == typeid(ESM::Clothing).name()) { @@ -265,7 +265,7 @@ void NpcAnimation::updateParts() addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); } } - if(mGloveR != mInv.end()) + if(mGloveR != mInv->end()) { if(mGloveR->getTypeName() == typeid(ESM::Clothing).name()) { @@ -282,13 +282,13 @@ void NpcAnimation::updateParts() } - if(mShirt != mInv.end()) + if(mShirt != mInv->end()) { const ESM::Clothing *clothes = (mShirt->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); } - if(mPants != mInv.end()) + if(mPants != mInv->end()) { const ESM::Clothing *clothes = (mPants->get())->mBase; std::vector parts = clothes->mParts.mParts; diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index ca76dcc22..fd1a96aa3 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -17,7 +17,7 @@ namespace MWRender{ class NpcAnimation: public Animation{ private: - MWWorld::InventoryStore& mInv; + MWWorld::InventoryStore *mInv; int mStateID; int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty @@ -78,7 +78,13 @@ public: virtual ~NpcAnimation(); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); virtual void runAnimation(float timepassed); + void updateParts(); + void updateParts(MWWorld::InventoryStore &inventory) { + mInv = &inventory; + updateParts(); + } + void removeEntities(NifOgre::EntityList &entities); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); From d983ed5c7819046ad4c0166c61f6cc47575196f7 Mon Sep 17 00:00:00 2001 From: greye Date: Fri, 22 Feb 2013 11:14:14 +0400 Subject: [PATCH 718/916] fix invalid SceneNode pointer on cell change --- apps/openmw/mwworld/worldimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ca054e776..12193de40 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -746,7 +746,11 @@ namespace MWWorld copyObjectToCell(ptr, newCell, pos); else if (!mWorldScene->isCellActive(newCell)) { - MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + MWWorld::Class::get(ptr) + .copyToCell(ptr, newCell) + .getRefData() + .setBaseNode(0); + mWorldScene->removeObjectFromScene(ptr); mLocalScripts.remove(ptr); removeContainerScripts (ptr); From ac7095537f9626f62ee9437b241371356b92526e Mon Sep 17 00:00:00 2001 From: greye Date: Sat, 23 Feb 2013 16:50:37 +0400 Subject: [PATCH 719/916] remove insertMesh() call on object cell change --- apps/openmw/mwrender/objects.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index ee36126f8..16ac163ec 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -514,9 +514,5 @@ void Objects::updateObjectCell(const MWWorld::Ptr &ptr) node = mCellSceneNodes[newCell]; } node->addChild(ptr.getRefData().getBaseNode()); - - /// \note Still unaware how to move aabb and static w/o full rebuild, - /// moving static objects may cause problems - insertMesh(ptr, MWWorld::Class::get(ptr).getModel(ptr)); } From a3adcf752d9796279f175d7fbd01080ac53b227f Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Fri, 22 Feb 2013 21:33:23 +0400 Subject: [PATCH 720/916] TradeWindow: fixed coding style Mentioned here: https://github.com/zinnschlag/openmw/pull/554 --- apps/openmw/mwgui/tradewindow.cpp | 12 ++++++------ apps/openmw/mwgui/tradewindow.hpp | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 2cc8ff444..290310760 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -19,11 +19,11 @@ #include "inventorywindow.hpp" -static const float BALANCE_CHANGE_INITIAL_PAUSE = 0.5; // in seconds -static const float BALANCE_CHANGE_INTERVAL = 0.1; // in seconds - namespace MWGui { + const float TradeWindow::sBalanceChangeInitialPause = 0.5; + const float TradeWindow::sBalanceChangeInterval = 0.1; + TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_trade_window.layout", parWindowManager) , ContainerBase(NULL) // no drag&drop @@ -157,7 +157,7 @@ namespace MWGui mBalanceChangePause -= frameDuration; if (mBalanceChangePause < 0.0) { - mBalanceChangePause += BALANCE_CHANGE_INTERVAL; + mBalanceChangePause += sBalanceChangeInterval; if (mBalanceButtonsState == BBS_Increase) onIncreaseButtonTriggered(); else if (mBalanceButtonsState == BBS_Decrease) @@ -296,14 +296,14 @@ namespace MWGui void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { mBalanceButtonsState = BBS_Increase; - mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + mBalanceChangePause = sBalanceChangeInitialPause; onIncreaseButtonTriggered(); } void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { mBalanceButtonsState = BBS_Decrease; - mBalanceChangePause = BALANCE_CHANGE_INITIAL_PAUSE; + mBalanceChangePause = sBalanceChangeInitialPause; onDecreaseButtonTriggered(); } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 20d9b6069..c1d31917b 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -37,6 +37,9 @@ namespace MWGui void onFrame(float frameDuration); protected: + static const float sBalanceChangeInitialPause; // in seconds + static const float sBalanceChangeInterval; // in seconds + MyGUI::Button* mFilterAll; MyGUI::Button* mFilterWeapon; MyGUI::Button* mFilterApparel; From e6da9dfae533065a4c258007160b3269c3407a09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 05:15:10 -0800 Subject: [PATCH 721/916] Specify the animation key to stop playing at --- apps/openmw/mwmechanics/character.cpp | 10 +++--- apps/openmw/mwrender/animation.cpp | 43 ++++++++++++++--------- apps/openmw/mwrender/animation.hpp | 11 +++--- apps/openmw/mwrender/characterpreview.cpp | 2 +- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7b166ba91..5598e0e56 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -113,7 +113,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop", loop); + mAnimation->play(mCurrentGroup, "stop", "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) @@ -152,7 +152,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", false); } else if(mAnimQueue.size() > 0) { @@ -160,7 +160,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", false); + mAnimation->play(mCurrentGroup, "start", "stop", false); } } return; @@ -247,7 +247,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), false); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", false); } else if(mode == 0) { @@ -283,7 +283,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 160641eb0..1dd46365b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -26,6 +26,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mCurrentKeys(NULL) , mCurrentAnim(NULL) , mCurrentTime(0.0f) + , mStopTime(0.0f) , mPlaying(false) , mLooping(false) , mAnimVelocity(0.0f) @@ -293,12 +294,12 @@ Ogre::Vector3 Animation::updatePosition(float time) return posdiff; } -void Animation::reset(const std::string &marker) +void Animation::reset(const std::string &start, const std::string &stop) { mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != marker) - mNextKey++; + while(mNextKey != mCurrentKeys->end() && mNextKey->second != start) + mNextKey++; if(mNextKey != mCurrentKeys->end()) mCurrentTime = mNextKey->first; else @@ -307,6 +308,17 @@ void Animation::reset(const std::string &marker) mCurrentTime = 0.0f; } + if(stop.length() > 0) + { + NifOgre::TextKeyMap::const_iterator stopKey = mNextKey; + while(stopKey != mCurrentKeys->end() && stopKey->second != stop) + stopKey++; + if(stopKey != mCurrentKeys->end()) + mStopTime = stopKey->first; + else + mStopTime = mCurrentAnim->getLength(); + } + if(mNonAccumRoot) { const Ogre::NodeAnimationTrack *track = 0; @@ -328,7 +340,7 @@ void Animation::reset(const std::string &marker) } -void Animation::play(const std::string &groupname, const std::string &start, bool loop) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { bool found = false; @@ -351,9 +363,9 @@ void Animation::play(const std::string &groupname, const std::string &start, boo if(!found) throw std::runtime_error("Failed to find animation "+groupname); - reset(start); + reset(start, stop); + setLooping(loop); mPlaying = true; - mLooping = loop; } catch(std::exception &e) { std::cerr<< e.what() <end() || mNextKey->first > targetTime) { movement += updatePosition(targetTime); - mPlaying = (mLooping || mCurrentAnim->getLength() >= targetTime); + mPlaying = (mLooping || mStopTime > targetTime); break; } @@ -380,6 +392,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) mNextKey++; movement += updatePosition(time); + mPlaying = (mLooping || mStopTime > time); + timepassed = targetTime - time; if(evt == "start" || evt == "loop start") @@ -391,7 +405,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - reset("loop start"); + reset("loop start", ""); if(mCurrentTime >= time) break; } @@ -401,17 +415,12 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) { if(mLooping) { - reset("loop start"); + reset("loop start", ""); if(mCurrentTime >= time) break; + continue; } - else - { - mPlaying = false; - if(mController) - mController->markerEvent(time, evt); - } - continue; + // fall-through } if(mController) mController->markerEvent(time, evt); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 130805a50..47bc8c390 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,6 +33,7 @@ protected: NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; float mCurrentTime; + float mStopTime; bool mPlaying; bool mLooping; @@ -53,9 +54,11 @@ protected: * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); - /* Resets the animation to the time of the specified marker, without moving - * anything. If the marker is not found, it resets to the beginning. */ - void reset(const std::string &marker); + /* Resets the animation to the time of the specified start marker, without + * moving anything, and set the end time to the specified stop marker. If + * the marker is not found, it resets to the beginning or end respectively. + */ + void reset(const std::string &start, const std::string &stop); /* Specifies a list of skeleton names to use as animation sources. */ void setAnimationSources(const std::vector &names); @@ -86,7 +89,7 @@ public: void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, bool loop); + void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); }; diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 9f8962d7c..36cac2155 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -145,7 +145,7 @@ namespace MWRender { mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, RV_PlayerPreview); - mAnimation->play("inventoryhandtohand", "start", false); + mAnimation->play("inventoryhandtohand", "start", "stop", false); } // -------------------------------------------------------------------------------------------------- From 3472a6f180e81ab510026b4b96760adf4d145181 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 14:40:56 +0100 Subject: [PATCH 722/916] workaround for infinite recursion during local variable access --- apps/openmw/mwscript/scriptmanagerimp.cpp | 42 +++++++++++++++-------- apps/openmw/mwscript/scriptmanagerimp.hpp | 1 + 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index 1f338edbd..e8489e3cd 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -140,25 +140,37 @@ namespace MWScript Compiler::Locals& ScriptManager::getLocals (const std::string& name) { - ScriptCollection::iterator iter = mScripts.find (name); - - if (iter==mScripts.end()) { - if (!compile (name)) - { - /// \todo Handle case of cyclic member variable access. Currently this could look up - /// the whole application in an endless recursion. + ScriptCollection::iterator iter = mScripts.find (name); - // failed -> ignore script from now on. - std::vector empty; - mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals()))); - throw std::runtime_error ("failed to compile script " + name); - } - - iter = mScripts.find (name); + if (iter!=mScripts.end()) + return iter->second.second; } - return iter->second.second; + { + std::map::iterator iter = mOtherLocals.find (name); + + if (iter!=mOtherLocals.end()) + return iter->second; + } + + Compiler::Locals locals; + + if (const ESM::Script *script = mStore.get().find (name)) + { + int index = 0; + + for (int i=0; imData.mNumShorts; ++i) + locals.declare ('s', script->mVarNames[index++]); + + for (int i=0; imData.mNumLongs; ++i) + locals.declare ('l', script->mVarNames[index++]); + + for (int i=0; imData.mNumFloats; ++i) + locals.declare ('f', script->mVarNames[index++]); + } + + throw std::logic_error ("script " + name + " does not exist"); } GlobalScripts& ScriptManager::getGlobalScripts() diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index c4a016eb7..1a856e0c5 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -47,6 +47,7 @@ namespace MWScript ScriptCollection mScripts; GlobalScripts mGlobalScripts; + std::map mOtherLocals; public: From 89dace3cc3bea36c7fec02b7b5bba629ab5e8e89 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 23 Feb 2013 09:07:13 -0600 Subject: [PATCH 723/916] Fix for operations widget - hides when no operations are running. --- apps/opencs/view/doc/operations.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index 71cacbe17..ce001afaa 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -16,7 +16,7 @@ CSVDoc::Operations::Operations() widgetContainer->setLayout (mLayout); setWidget (widgetContainer); - + setVisible (false); setFixedHeight (widgetContainer->height()); setTitleBarWidget (new QWidget (this)); } @@ -42,6 +42,8 @@ void CSVDoc::Operations::setProgress (int current, int max, int type, int thread if ( oldCount > 0) setFixedHeight (height()/oldCount * newCount); + + setVisible (true); } void CSVDoc::Operations::quitOperation (int type) @@ -59,6 +61,8 @@ void CSVDoc::Operations::quitOperation (int type) if (oldCount > 1) setFixedHeight (height() / oldCount * newCount); + else + setVisible (false); break; } From 0d0e75fe0b74c265e6ae31a5dccfa2e240fc196e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 07:36:11 -0800 Subject: [PATCH 724/916] Don't set animation sources for models that don't have a skeleton --- apps/openmw/mwrender/animation.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1dd46365b..29652ca6a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -49,6 +49,9 @@ Animation::~Animation() void Animation::setAnimationSources(const std::vector &names) { + if(!mEntityList.mSkelBase) + return; + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); mCurrentAnim = NULL; @@ -59,7 +62,7 @@ void Animation::setAnimationSources(const std::vector &names) mSkeletonSources.clear(); std::vector::const_iterator nameiter = names.begin(); - while(nameiter != names.end()) + for(nameiter = names.begin();nameiter != names.end();nameiter++) { Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); if(skel.isNull()) @@ -69,7 +72,6 @@ void Animation::setAnimationSources(const std::vector &names) if(skel.isNull()) { std::cerr<< "Failed to get skeleton source "<<*nameiter < &names) if(data.isEmpty() || !Ogre::any_cast(data)) continue; - if(!mNonAccumRoot && mEntityList.mSkelBase) + if(!mNonAccumRoot) { mAccumRoot = mInsert; mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); @@ -102,8 +104,6 @@ void Animation::setAnimationSources(const std::vector &names) break; } - - nameiter++; } } From a2eaec787802d80f62917e13037b75e696d04213 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 08:03:52 -0800 Subject: [PATCH 725/916] Avoiding holding the InventoryStore in the NpcAnimation class --- apps/openmw/mwrender/actors.cpp | 6 +---- apps/openmw/mwrender/npcanimation.cpp | 34 ++++++++++++++------------- apps/openmw/mwrender/npcanimation.hpp | 12 ++++------ 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 3f3145900..d356d922e 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -167,11 +167,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) PtrAnimationMap::iterator iter = mAllActors.find(ptr); if(iter != mAllActors.end()) { - /// \note Update key (Ptr's are compared only with refdata so mCell - /// on key is outdated), maybe redundant - NpcAnimation *anim = static_cast(iter->second); - anim->updateParts(MWWorld::Class::get(ptr).getInventoryStore(ptr)); - + Animation *anim = iter->second; mAllActors.erase(iter); mAllActors[ptr] = anim; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index dcaee55f9..809e3f6d2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -5,6 +5,8 @@ #include #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -54,22 +56,21 @@ NpcAnimation::~NpcAnimation() NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) : Animation(ptr), - mInv(&inv), mStateID(-1), mTimeToChange(0), mVisibilityFlags(visibilityFlags), - mRobe(mInv->end()), - mHelmet(mInv->end()), - mShirt(mInv->end()), - mCuirass(mInv->end()), - mGreaves(mInv->end()), - mPauldronL(mInv->end()), - mPauldronR(mInv->end()), - mBoots(mInv->end()), - mPants(mInv->end()), - mGloveL(mInv->end()), - mGloveR(mInv->end()), - mSkirtIter(mInv->end()) + mRobe(inv.end()), + mHelmet(inv.end()), + mShirt(inv.end()), + mCuirass(inv.end()), + mGreaves(inv.end()), + mPauldronL(inv.end()), + mPauldronR(inv.end()), + mBoots(inv.end()), + mPants(inv.end()), + mGloveL(inv.end()), + mGloveR(inv.end()), + mSkirtIter(inv.end()) { mNpc = mPtr.get()->mBase; @@ -213,9 +214,10 @@ void NpcAnimation::updateParts(bool forceupdate) }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); + MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); for(size_t i = 0;!forceupdate && i < slotlistsize;i++) { - MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); if(this->*slotlist[i].part != iter) { forceupdate = true; @@ -227,12 +229,12 @@ void NpcAnimation::updateParts(bool forceupdate) for(size_t i = 0;i < slotlistsize;i++) { - MWWorld::ContainerStoreIterator iter = mInv->getSlot(slotlist[i].slot); + MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); this->*slotlist[i].part = iter; removePartGroup(slotlist[i].slot); - if(this->*slotlist[i].part == mInv->end()) + if(this->*slotlist[i].part == inv.end()) continue; for(int rem = 0;rem < slotlist[i].numRemoveParts;rem++) diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index c5d5b7461..aed4868bd 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -3,7 +3,6 @@ #include "animation.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/containerstore.hpp" namespace ESM @@ -11,6 +10,11 @@ namespace ESM struct NPC; } +namespace MWWorld +{ + class InventoryStore; +} + namespace MWRender { @@ -26,7 +30,6 @@ private: static const size_t sPartListSize = 27; static const PartInfo sPartList[sPartListSize]; - MWWorld::InventoryStore *mInv; int mStateID; // Bounded Parts @@ -75,11 +78,6 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); - void updateParts(MWWorld::InventoryStore &inventory) - { - mInv = &inventory; - updateParts(true); - } void forceUpdate() { updateParts(true); } }; From 61fc8ad6e4bed33473c891b3268d91bc2168a56e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 18:56:07 +0100 Subject: [PATCH 726/916] updated credits files --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 5c966d86b..8b396aad0 100644 --- a/credits.txt +++ b/credits.txt @@ -40,6 +40,7 @@ Nikolay Kasyanov (corristo) Pieter van der Kloet (pvdk) Roman Melnik (Kromgart) Sebastian Wick (swick) +Sergey Shambir Sylvain T. (Garvek) Tom Mason (wheybags) From d208422ca76da90b9a5a0fa12b47722122948b8e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 10:12:36 -0800 Subject: [PATCH 727/916] Add a method to update an Animation's Ptr object --- apps/openmw/mwrender/actors.cpp | 1 + apps/openmw/mwrender/animation.cpp | 5 +++++ apps/openmw/mwrender/animation.hpp | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index d356d922e..485e3a7ad 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -169,6 +169,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) { Animation *anim = iter->second; mAllActors.erase(iter); + anim->updatePtr(ptr); mAllActors[ptr] = anim; } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 29652ca6a..39323edac 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,6 +169,11 @@ void Animation::setLooping(bool loop) mLooping = loop; } +void Animation::updatePtr(const MWWorld::Ptr &ptr) +{ + mPtr = ptr; +} + void Animation::calcAnimVelocity() { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 47bc8c390..b8323cb89 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -49,7 +49,6 @@ protected: * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); - /* Updates the animation to the specified time, and returns the movement * vector since the last update or reset. */ Ogre::Vector3 updatePosition(float time); @@ -78,6 +77,8 @@ public: void setController(MWMechanics::CharacterController *controller); + void updatePtr(const MWWorld::Ptr &ptr); + bool hasAnimation(const std::string &anim); // Specifies the axis' to accumulate on. Non-accumulated axis will just From 44b1c66c4b1a976024ac1f664793d80737cd27ce Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 14 Feb 2013 21:38:27 -0800 Subject: [PATCH 728/916] fixed various warnings about converting size_t to int --- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/store.hpp | 16 ++++++++-------- components/esm/esmwriter.cpp | 10 +++++----- components/esm/esmwriter.hpp | 8 ++++---- components/to_utf8/to_utf8.cpp | 4 ++-- components/to_utf8/to_utf8.hpp | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b917a8916..254e05e7f 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -25,7 +25,7 @@ namespace const MWWorld::Class& class_ = MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); - int numRefs = cellRefList.mList.size(); + size_t numRefs = cellRefList.mList.size(); int current = 0; for (typename T::List::iterator it = cellRefList.mList.begin(); it != cellRefList.mList.end(); it++) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index cb18873cc..c05e37283 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -17,7 +17,7 @@ namespace MWWorld virtual void setUp() {} virtual void listIdentifier(std::vector &list) const {} - virtual int getSize() const = 0; + virtual size_t getSize() const = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; virtual bool eraseStatic(const std::string &id) {return false;} @@ -158,7 +158,7 @@ namespace MWWorld return mShared.end(); } - int getSize() const { + size_t getSize() const { return mShared.size(); } @@ -269,11 +269,11 @@ namespace MWWorld return ptr; } - int getSize() const { + size_t getSize() const { return mStatic.size(); } - int getSize(size_t plugin) const { + size_t getSize(size_t plugin) const { assert(plugin < mStatic.size()); return mStatic[plugin].size(); } @@ -338,7 +338,7 @@ namespace MWWorld } - int getSize() const { + size_t getSize() const { return mStatic.size(); } @@ -567,7 +567,7 @@ namespace MWWorld return 0; } - int getSize() const { + size_t getSize() const { return mSharedInt.size() + mSharedExt.size(); } @@ -701,7 +701,7 @@ namespace MWWorld mStatic.back().load(esm); } - int getSize() const { + size_t getSize() const { return mStatic.size(); } @@ -930,7 +930,7 @@ namespace MWWorld } } - int getSize() const { + size_t getSize() const { return mStatic.size(); } diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index e2f878a25..b9dd5b57b 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -136,15 +136,15 @@ void ESMWriter::writeHNString(const std::string& name, const std::string& data) endRecord(name); } -void ESMWriter::writeHNString(const std::string& name, const std::string& data, int size) +void ESMWriter::writeHNString(const std::string& name, const std::string& data, size_t size) { - assert(static_cast (data.size()) <= size); + assert(data.size() <= size); startSubRecord(name); writeHString(data); - if (static_cast (data.size()) < size) + if (data.size() < size) { - for (int i = data.size(); i < size; ++i) + for (size_t i = data.size(); i < size; ++i) write("\0",1); } @@ -177,7 +177,7 @@ void ESMWriter::writeName(const std::string& name) write(name.c_str(), name.size()); } -void ESMWriter::write(const char* data, int size) +void ESMWriter::write(const char* data, size_t size) { if (count && !m_records.empty()) { diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index b557a29ad..94e173b4c 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -16,7 +16,7 @@ class ESMWriter { std::string name; std::streampos position; - int size; + size_t size; }; public: @@ -35,7 +35,7 @@ public: void close(); void writeHNString(const std::string& name, const std::string& data); - void writeHNString(const std::string& name, const std::string& data, int size); + void writeHNString(const std::string& name, const std::string& data, size_t size); void writeHNCString(const std::string& name, const std::string& data) { startSubRecord(name); @@ -76,7 +76,7 @@ public: } template - void writeT(const T& data, int size) + void writeT(const T& data, size_t size) { write((char*)&data, size); } @@ -87,7 +87,7 @@ public: void writeHString(const std::string& data); void writeHCString(const std::string& data); void writeName(const std::string& data); - void write(const char* data, int size); + void write(const char* data, size_t size); private: std::list m_masters; diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index e2a1b1220..1de15d79c 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -70,7 +70,7 @@ Utf8Encoder::Utf8Encoder(const FromType sourceEncoding): } } -std::string Utf8Encoder::getUtf8(const char* input, int size) +std::string Utf8Encoder::getUtf8(const char* input, size_t size) { // Double check that the input string stops at some point (it might // contain zero terminators before this, inside its own data, which @@ -111,7 +111,7 @@ std::string Utf8Encoder::getUtf8(const char* input, int size) return std::string(&mOutput[0], outlen); } -std::string Utf8Encoder::getLegacyEnc(const char *input, int size) +std::string Utf8Encoder::getLegacyEnc(const char *input, size_t size) { // Double check that the input string stops at some point (it might // contain zero terminators before this, inside its own data, which diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index d975b3e4d..839aa36aa 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -27,13 +27,13 @@ namespace ToUTF8 Utf8Encoder(FromType sourceEncoding); // Convert to UTF8 from the previously given code page. - std::string getUtf8(const char *input, int size); + std::string getUtf8(const char *input, size_t size); inline std::string getUtf8(const std::string &str) { return getUtf8(str.c_str(), str.size()); } - std::string getLegacyEnc(const char *input, int size); + std::string getLegacyEnc(const char *input, size_t size); inline std::string getLegacyEnc(const std::string &str) { return getLegacyEnc(str.c_str(), str.size()); From 1af4e11414c94e4691acefb2fe987790570ae8b4 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 23 Feb 2013 10:24:18 -0800 Subject: [PATCH 729/916] apply MSVC warning settings to shiny projects --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ef85e34d..95d54fed1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -529,6 +529,8 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) + set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${WARNINGS}) + set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) if (BUILD_LAUNCHER) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) From a95431c387258d0f3862a9e8a5345336602a4cb2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Feb 2013 20:20:40 +0100 Subject: [PATCH 730/916] fix --- apps/openmw/mwscript/scriptmanagerimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index e8489e3cd..fed5877c4 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -168,6 +168,11 @@ namespace MWScript for (int i=0; imData.mNumFloats; ++i) locals.declare ('f', script->mVarNames[index++]); + + std::map::iterator iter = + mOtherLocals.insert (std::make_pair (name, locals)).first; + + return iter->second; } throw std::logic_error ("script " + name + " does not exist"); From df8889dcc4eb772a8689252e940ba1275d8fd2fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 13:15:37 -0800 Subject: [PATCH 731/916] Limit maximum frame time to 200ms This effectively slows game time when it drops below 5 fps. Something like this is desirable when dealing with time-based animations, which can jump forward after a lengthy cell transition. --- apps/openmw/engine.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7dc18c6e8..6f59349fd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -67,14 +67,15 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { - mEnvironment.setFrameDuration (evt.timeSinceLastFrame); + float frametime = std::min(evt.timeSinceLastFrame, 0.2f); + mEnvironment.setFrameDuration(frametime); // update input - MWBase::Environment::get().getInputManager()->update(evt.timeSinceLastFrame, false); + MWBase::Environment::get().getInputManager()->update(frametime, false); // sound if (mUseSound) - MWBase::Environment::get().getSoundManager()->update (evt.timeSinceLastFrame); + MWBase::Environment::get().getSoundManager()->update(frametime); // global scripts MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); @@ -88,19 +89,19 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // passing of time if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) - MWBase::Environment::get().getWorld()->advanceTime ( - mEnvironment.getFrameDuration()*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); + MWBase::Environment::get().getWorld()->advanceTime( + frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); if (changed) // keep change flag for another frame, if cell changed happend in local script MWBase::Environment::get().getWorld()->markCellAsUnchanged(); // update actors - MWBase::Environment::get().getMechanicsManager()->update(mEnvironment.getFrameDuration(), + MWBase::Environment::get().getMechanicsManager()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); // update world - MWBase::Environment::get().getWorld()->update (evt.timeSinceLastFrame, MWBase::Environment::get().getWindowManager()->isGuiMode()); + MWBase::Environment::get().getWorld()->update(frametime, MWBase::Environment::get().getWindowManager()->isGuiMode()); // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); @@ -108,7 +109,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); - MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); + MWBase::Environment::get().getWindowManager()->onFrame(frametime); } catch (const std::exception& e) { From d77d035d3a32fe7eefd567068572c805a17a5e97 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 14:15:11 -0800 Subject: [PATCH 732/916] Handle the "sound" events in runAnimation --- apps/openmw/mwmechanics/character.cpp | 14 -------------- apps/openmw/mwrender/animation.cpp | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5598e0e56..37477932a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -24,7 +24,6 @@ #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -134,19 +133,6 @@ CharacterController::~CharacterController() void CharacterController::markerEvent(float time, const std::string &evt) { - if(evt.compare(0, 7, "sound: ") == 0) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); - return; - } - if(evt.compare(0, 10, "soundgen: ") == 0) - { - // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds - // to this actor type - return; - } - if(evt == "stop") { if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 39323edac..f453e6a74 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -8,6 +8,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwbase/world.hpp" #include "../mwmechanics/character.hpp" @@ -406,6 +407,20 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) /* Do nothing */ continue; } + + if(evt.compare(0, 7, "sound: ") == 0) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + continue; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + continue; + } + if(evt == "loop stop") { if(mLooping) From 150d4a7a7292bd1d6cc86bcd4d3177635111e146 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sat, 23 Feb 2013 23:18:42 +0100 Subject: [PATCH 733/916] Added support for multiple ini files --- apps/launcher/maindialog.cpp | 23 +++++++++++++++++++---- apps/launcher/settings/gamesettings.cpp | 18 ++---------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 77526677b..c03a31fd5 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -180,7 +180,7 @@ bool MainDialog::showFirstRunDialog() if (msgBox.clickedButton() == importerButton) { - QString iniPath; + QStringList iniPaths; foreach (const QString &path, mGameSettings.getDataDirs()) { QDir dir(path); @@ -190,10 +190,10 @@ bool MainDialog::showFirstRunDialog() continue; // Cannot move from Data Files if (dir.exists(QString("Morrowind.ini"))) - iniPath = dir.absoluteFilePath(QString("Morrowind.ini")); + iniPaths.append(dir.absoluteFilePath(QString("Morrowind.ini"))); } - if (iniPath.isEmpty()) { + if (iniPaths.isEmpty()) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Error reading Morrowind configuration file")); msgBox.setIcon(QMessageBox::Warning); @@ -205,6 +205,21 @@ bool MainDialog::showFirstRunDialog() return false; } + if (iniPaths.count() > 1) { + // Multiple Morrowind.ini files found + bool ok; + QString path = QInputDialog::getItem(this, tr("Multiple configurations found"), + tr("
There are multiple Morrowind.ini files found.

\ + Please select the one you wish to import from:"), iniPaths, 0, false, &ok); + if (ok && !path.isEmpty()) { + iniPaths.clear(); + iniPaths.append(path); + } else { + // Cancel was clicked TODO: should we abort here? + return false; + } + } + // Create the file if it doesn't already exist, else the importer will fail QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg"); QFile file(path); @@ -232,7 +247,7 @@ bool MainDialog::showFirstRunDialog() if (msgBox.isChecked()) arguments.append(QString("-g")); - arguments.append(iniPath); + arguments.append(iniPaths.first()); arguments.append(path); if (!startProgram(QString("mwiniimport"), arguments, false)) diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 20ccebc97..6b46a5160 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -21,11 +21,10 @@ GameSettings::~GameSettings() void GameSettings::validatePaths() { - if (mSettings.isEmpty()) - return; + if (mSettings.isEmpty() || !mDataDirs.isEmpty()) + return; // Don't re-validate paths if they are already parsed QStringList paths = mSettings.values(QString("data")); - qDebug() << "paths " << paths; Files::PathContainer dataDirs; foreach (const QString &path, paths) { @@ -89,19 +88,6 @@ bool GameSettings::readFile(QTextStream &stream) QString key = keyRe.cap(1).simplified(); QString value = keyRe.cap(2).simplified(); -// // There can be multiple keys -// if (key == QLatin1String("data") || -// key == QLatin1String("master") || -// key == QLatin1String("plugin")) -// { -// // Remove keys from previous config and overwrite them -// mSettings.remove(key); -// QStringList values = cache.values(key); -// if (!values.contains(value)) // Do not insert duplicate values -// cache.insertMulti(key, value); -// } else { -// cache.insert(key, value); -// } mSettings.remove(key); QStringList values = cache.values(key); From 8e59ea494171740fb7b80d0e8f87ee7a24536f77 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 14:39:01 -0800 Subject: [PATCH 734/916] Use a separate method to handle animation events --- apps/openmw/mwrender/animation.cpp | 92 ++++++++++++++++-------------- apps/openmw/mwrender/animation.hpp | 2 + 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f453e6a74..394e25b50 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -346,6 +346,54 @@ void Animation::reset(const std::string &start, const std::string &stop) } +bool Animation::handleEvent(float time, const std::string &evt) +{ + if(evt == "start" || evt == "loop start") + { + /* Do nothing */ + return true; + } + + if(evt.compare(0, 7, "sound: ") == 0) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); + return true; + } + if(evt.compare(0, 10, "soundgen: ") == 0) + { + // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds + // to this actor type + return true; + } + + if(evt == "loop stop") + { + if(mLooping) + { + reset("loop start", ""); + if(mCurrentTime >= time) + return false; + } + return true; + } + if(evt == "stop") + { + if(mLooping) + { + reset("loop start", ""); + if(mCurrentTime >= time) + return false; + return true; + } + // fall-through + } + if(mController) + mController->markerEvent(time, evt); + return true; +} + + void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { @@ -402,48 +450,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) timepassed = targetTime - time; - if(evt == "start" || evt == "loop start") - { - /* Do nothing */ - continue; - } - - if(evt.compare(0, 7, "sound: ") == 0) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f); - continue; - } - if(evt.compare(0, 10, "soundgen: ") == 0) - { - // FIXME: Lookup the SoundGen (SNDG) for the specified sound that corresponds - // to this actor type - continue; - } - - if(evt == "loop stop") - { - if(mLooping) - { - reset("loop start", ""); - if(mCurrentTime >= time) - break; - } - continue; - } - if(evt == "stop") - { - if(mLooping) - { - reset("loop start", ""); - if(mCurrentTime >= time) - break; - continue; - } - // fall-through - } - if(mController) - mController->markerEvent(time, evt); + if(!handleEvent(time, evt)) + break; } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b8323cb89..810ca869f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -59,6 +59,8 @@ protected: */ void reset(const std::string &start, const std::string &stop); + bool handleEvent(float time, const std::string &evt); + /* Specifies a list of skeleton names to use as animation sources. */ void setAnimationSources(const std::vector &names); From a5ff8181b737b91f096b1182f03066ac14ef0e06 Mon Sep 17 00:00:00 2001 From: lazydev Date: Sun, 24 Feb 2013 03:35:43 +0400 Subject: [PATCH 735/916] fix for https://bugs.openmw.org/issues/569 --- apps/openmw/mwworld/store.hpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index cb18873cc..3eec05234 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -19,7 +19,7 @@ namespace MWWorld virtual int getSize() const = 0; virtual void load(ESM::ESMReader &esm, const std::string &id) = 0; - + virtual bool eraseStatic(const std::string &id) {return false;} }; @@ -110,7 +110,7 @@ namespace MWWorld item.mId = Misc::StringUtils::lowerCase(id); typename std::map::const_iterator it = mStatic.find(item.mId); - + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { return &(it->second); } @@ -188,14 +188,14 @@ namespace MWWorld item.mId = Misc::StringUtils::lowerCase(id); typename std::map::iterator it = mStatic.find(item.mId); - + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { mStatic.erase(it); } return true; } - + bool erase(const std::string &id) { std::string key = Misc::StringUtils::lowerCase(id); typename Dynamic::iterator it = mDynamic.find(key); @@ -220,9 +220,15 @@ namespace MWWorld template <> inline void Store::load(ESM::ESMReader &esm, const std::string &id) { std::string idLower = Misc::StringUtils::lowerCase(id); - mStatic[idLower] = ESM::Dialogue(); - mStatic[idLower].mId = id; // don't smash case here, as this line is printed... I think - mStatic[idLower].load(esm); + + std::map::iterator it = mStatic.find(idLower); + if (it == mStatic.end()) { + it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; + it->second.mId = id; // don't smash case here, as this line is printed... I think + } + + //I am not sure is it need to load the dialog from a plugin if it was already loaded from prevois plugins + it->second.load(esm); } template <> @@ -409,7 +415,7 @@ namespace MWWorld DynamicInt mDynamicInt; DynamicExt mDynamicExt; - + const ESM::Cell *search(const ESM::Cell &cell) const { if (cell.isExterior()) { return search(cell.getGridX(), cell.getGridY()); @@ -481,7 +487,7 @@ namespace MWWorld newCell->mData.mY = y; mExt[std::make_pair(x, y)] = *newCell; delete newCell; - + return &mExt[std::make_pair(x, y)]; } @@ -528,7 +534,7 @@ namespace MWWorld // There some nasty three-way cyclic header dependency involved, which I could only fix by moving // this method. void load(ESM::ESMReader &esm, const std::string &id); - + iterator intBegin() const { return iterator(mSharedInt.begin()); } From 90cb9ee0ac73dca6388b2f69e1906945d51e4fab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 23 Feb 2013 16:30:11 -0800 Subject: [PATCH 736/916] Don't set a vertical velocity when on the ground --- apps/openmw/mwworld/physicssystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 9b9c9afea..0c1f58048 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -190,7 +190,7 @@ namespace MWWorld onground = false; } physicActor->setOnGround(onground); - physicActor->setVerticalForce(clippedVelocity.z - time*627.2f); + physicActor->setVerticalForce(!onground ? clippedVelocity.z - time*627.2f : 0.0f); return newPosition; } From 9198afeefb3a50bcefe3ff4f4f56d22e63f73b90 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 24 Feb 2013 03:10:27 +0100 Subject: [PATCH 737/916] Improved context menu, added context menu for masters and added multi-selection support --- apps/launcher/datafilespage.cpp | 186 ++++++++++++++++++++------------ apps/launcher/datafilespage.hpp | 9 +- 2 files changed, 119 insertions(+), 76 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 4ecb67e4e..60e377afb 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -99,9 +99,10 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mMastersTable = new QTableView(this); mMastersTable->setModel(mMastersProxyModel); mMastersTable->setObjectName("MastersTable"); + mMastersTable->setContextMenuPolicy(Qt::CustomContextMenu); mMastersTable->setSortingEnabled(false); mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mMastersTable->setSelectionMode(QAbstractItemView::SingleSelection); + mMastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); mMastersTable->setAlternatingRowColors(true); mMastersTable->horizontalHeader()->setStretchLastSection(true); @@ -118,7 +119,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); mPluginsTable->setSortingEnabled(false); mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mPluginsTable->setSelectionMode(QAbstractItemView::SingleSelection); + mPluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); mPluginsTable->setAlternatingRowColors(true); mPluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); @@ -173,6 +174,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(mMastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); @@ -208,15 +210,13 @@ void DataFilesPage::createActions() mProfileToolBar->addAction(mDeleteProfileAction); // Context menu actions - mCheckAction = new QAction(tr("Check selected"), this); + mCheckAction = new QAction(tr("Check Selection"), this); connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check())); - mUncheckAction = new QAction(tr("Uncheck selected"), this); + mUncheckAction = new QAction(tr("Uncheck Selection"), this); connect(mUncheckAction, SIGNAL(triggered()), this, SLOT(uncheck())); - // Context menu for the plugins table mContextMenu = new QMenu(this); - mContextMenu->addAction(mCheckAction); mContextMenu->addAction(mUncheckAction); } @@ -296,6 +296,9 @@ void DataFilesPage::loadSettings() void DataFilesPage::saveSettings() { + if (mDataFilesModel->rowCount() < 1) + return; + QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); if (profile.isEmpty()) @@ -406,54 +409,21 @@ void DataFilesPage::deleteProfile() void DataFilesPage::check() { - // Check the current selection - if (!mPluginsTable->selectionModel()->hasSelection()) { - return; - } + if (mPluginsTable->hasFocus()) + setPluginsCheckstates(Qt::Checked); - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + if (mMastersTable->hasFocus()) + setMastersCheckstates(Qt::Checked); - //sort selection ascending because selectedIndexes returns an unsorted list - //qSort(indexes.begin(), indexes.end(), rowSmallerThan); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); - - if (!sourceIndex.isValid()) - return; - - mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); - } } void DataFilesPage::uncheck() { - // uncheck the current selection - if (!mPluginsTable->selectionModel()->hasSelection()) { - return; - } + if (mPluginsTable->hasFocus()) + setPluginsCheckstates(Qt::Unchecked); - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); - - //sort selection ascending because selectedIndexes returns an unsorted list - //qSort(indexes.begin(), indexes.end(), rowSmallerThan); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); - - if (!sourceIndex.isValid()) - return; - - mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked); - } + if (mMastersTable->hasFocus()) + setMastersCheckstates(Qt::Unchecked); } void DataFilesPage::refresh() @@ -464,6 +434,50 @@ void DataFilesPage::refresh() mPluginsTable->scrollToTop(); } +void DataFilesPage::setMastersCheckstates(Qt::CheckState state) +{ + if (!mMastersTable->selectionModel()->hasSelection()) { + return; + } + + QModelIndexList indexes = mMastersTable->selectionModel()->selectedIndexes(); + + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + return; + + QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); + + if (!sourceIndex.isValid()) + return; + + mDataFilesModel->setCheckState(sourceIndex, state); + } +} + +void DataFilesPage::setPluginsCheckstates(Qt::CheckState state) +{ + if (!mPluginsTable->selectionModel()->hasSelection()) { + return; + } + + QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + return; + + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + mDataFilesModel->setCheckState(sourceIndex, state); + } +} void DataFilesPage::setCheckState(QModelIndex index) { @@ -554,35 +568,69 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre void DataFilesPage::showContextMenu(const QPoint &point) { - // Make sure there are plugins in the view - if (!mPluginsTable->selectionModel()->hasSelection()) { + QObject *object = QObject::sender(); + + // Not a signal-slot call + if (!object) return; - } - QPoint globalPos = mPluginsTable->mapToGlobal(point); - - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); - - // Show the check/uncheck actions depending on the state of the selected items - mUncheckAction->setEnabled(false); - mCheckAction->setEnabled(false); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) + if (object->objectName() == QLatin1String("PluginsTable")) { + if (!mPluginsTable->selectionModel()->hasSelection()) return; - QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( - mFilterProxyModel->mapToSource(index)); + QPoint globalPos = mPluginsTable->mapToGlobal(point); + QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); - if (!sourceIndex.isValid()) - return; + // Show the check/uncheck actions depending on the state of the selected items + mUncheckAction->setEnabled(false); + mCheckAction->setEnabled(false); - (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mUncheckAction->setEnabled(true) - : mCheckAction->setEnabled(true); + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + return; + + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (!sourceIndex.isValid()) + return; + + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mUncheckAction->setEnabled(true) + : mCheckAction->setEnabled(true); + } + + // Show menu + mContextMenu->exec(globalPos); } - // Show menu - mContextMenu->exec(globalPos); + if (object->objectName() == QLatin1String("MastersTable")) { + if (!mMastersTable->selectionModel()->hasSelection()) + return; + QPoint globalPos = mMastersTable->mapToGlobal(point); + QModelIndexList indexes = mMastersTable->selectionModel()->selectedIndexes(); + + // Show the check/uncheck actions depending on the state of the selected items + mUncheckAction->setEnabled(false); + mCheckAction->setEnabled(false); + + foreach (const QModelIndex &index, indexes) + { + if (!index.isValid()) + return; + + QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); + + if (!sourceIndex.isValid()) + return; + + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mUncheckAction->setEnabled(true) + : mCheckAction->setEnabled(true); + } + + mContextMenu->exec(globalPos); + } } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 2561aa3d1..dd69d7489 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -37,7 +37,6 @@ public: public slots: void setCheckState(QModelIndex index); - void filterChanged(const QString filter); void showContextMenu(const QPoint &point); void profileChanged(const QString &previous, const QString ¤t); @@ -49,10 +48,6 @@ public slots: // Action slots void newProfile(); void deleteProfile(); -// void moveUp(); -// void moveDown(); -// void moveTop(); -// void moveBottom(); void check(); void uncheck(); void refresh(); @@ -90,8 +85,8 @@ private: TextInputDialog *mNewProfileDialog; -// const QStringList checkedPlugins(); -// const QStringList selectedMasters(); + void setMastersCheckstates(Qt::CheckState state); + void setPluginsCheckstates(Qt::CheckState state); void createActions(); void setupDataFiles(); From be43fa334f88a4271d1201cd392d5f000f81aede Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 24 Feb 2013 03:14:19 +0100 Subject: [PATCH 738/916] Added support for non-latin characters, fixes Bug #515 --- apps/launcher/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index a5c6e30a5..09da1d615 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "maindialog.hpp" @@ -29,6 +30,9 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); + // Support non-latin characters + QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); + MainDialog mainWin; if (mainWin.setup()) { From 4737b20e4cf46f0bb7165fb4a1e1d2d013aedde0 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 24 Feb 2013 04:00:22 +0100 Subject: [PATCH 739/916] Fixed a bug in the combobox popup font size, items overlapping --- apps/launcher/playpage.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index cb993a8fa..1dbc1b9df 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -15,10 +15,15 @@ PlayPage::PlayPage(QWidget *parent) : QWidget(parent) QLabel *profileLabel = new QLabel(tr("Current Profile:"), playWidget); profileLabel->setObjectName("ProfileLabel"); + // Hacks to get the stylesheet look properly on different platforms QPlastiqueStyle *style = new QPlastiqueStyle; + QFont font = QApplication::font(); + font.setPointSize(12); // Fixes problem with overlapping items + mProfilesComboBox = new QComboBox(playWidget); mProfilesComboBox->setObjectName("ProfilesComboBox"); mProfilesComboBox->setStyle(style); + mProfilesComboBox->setFont(font); QGridLayout *playLayout = new QGridLayout(playWidget); @@ -40,4 +45,4 @@ PlayPage::PlayPage(QWidget *parent) : QWidget(parent) pageLayout->addWidget(playWidget); -} \ No newline at end of file +} From 919d1ee5728cd15527d73e38a5b875d84ffdc171 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 24 Feb 2013 04:14:18 +0100 Subject: [PATCH 740/916] Some fixes to the settings handlers --- apps/launcher/settings/gamesettings.cpp | 19 ++++--------------- apps/launcher/settings/settingsbase.hpp | 8 -------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 6b46a5160..c08179acc 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -88,7 +88,9 @@ bool GameSettings::readFile(QTextStream &stream) QString key = keyRe.cap(1).simplified(); QString value = keyRe.cap(2).simplified(); - mSettings.remove(key); + // Don't remove existing data entries + if (key != QLatin1String("data")) + mSettings.remove(key); QStringList values = cache.values(key); if (!values.contains(value)) { @@ -103,19 +105,6 @@ bool GameSettings::readFile(QTextStream &stream) return true; } - // Replace values from previous settings - QMapIterator i(cache); - while (i.hasNext()) { - i.next(); - - // Don't remove existing data entries - if (i.key() == QLatin1String("data")) - continue; - - if (mSettings.contains(i.key())) - mSettings.remove(i.key()); - } - // Merge the changed keys with those which didn't mSettings.unite(cache); validatePaths(); @@ -136,7 +125,7 @@ bool GameSettings::writeFile(QTextStream &stream) continue; // Quote paths with spaces - if (i.key() == QLatin1String("data") || i.key() == QLatin1String("data")) { + if (i.key() == QLatin1String("data")) { if (i.value().contains(" ")) { stream << i.key() << "=\"" << i.value() << "\"\n"; continue; diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 321426eed..bbfad1fbb 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -85,14 +85,6 @@ public: return true; } - // Replace values from previous settings - QMapIterator i(mCache); - while (i.hasNext()) { - i.next(); - if (mSettings.contains(i.key())) - mSettings.remove(i.key()); - } - // Merge the changed keys with those which didn't mSettings.unite(mCache); return true; From 0d6a3367d3693adc7d760b77ec1766c7ee532fbd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 10:28:50 +0100 Subject: [PATCH 741/916] Water shader no longer depends on object shaders being enabled --- apps/openmw/mwgui/settingswindow.cpp | 35 +++++++++++----------------- files/materials/water.mat | 4 +++- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 54c2ef197..ebeb42ab2 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -264,16 +264,9 @@ namespace MWGui mRefractionButton->setCaptionWithReplacing (Settings::Manager::getBool("refraction", "Water") ? "#{sOn}" : "#{sOff}"); - if (!MWRender::RenderingManager::waterShaderSupported()) - { - mWaterShaderButton->setEnabled(false); - mReflectObjectsButton->setEnabled(false); - mReflectActorsButton->setEnabled(false); - mReflectTerrainButton->setEnabled(false); - } - if (!Settings::Manager::getBool("shaders", "Objects")) { + mRefractionButton->setEnabled(false); mUnderwaterButton->setEnabled (false); mShadowsEnabledButton->setEnabled(false); } @@ -466,15 +459,15 @@ namespace MWGui { Settings::Manager::setBool("shaders", "Objects", false); - // water shader not supported with object shaders off - mWaterShaderButton->setCaptionWithReplacing("#{sOff}"); mUnderwaterButton->setCaptionWithReplacing("#{sOff}"); - mWaterShaderButton->setEnabled(false); - mReflectObjectsButton->setEnabled(false); - mReflectActorsButton->setEnabled(false); - mReflectTerrainButton->setEnabled(false); + mUnderwaterButton->setEnabled(false); - Settings::Manager::setBool("shader", "Water", false); + + // refraction needs shaders to display underwater fog + mRefractionButton->setCaptionWithReplacing("#{sOff}"); + mRefractionButton->setEnabled(false); + + Settings::Manager::setBool("refraction", "Water", false); Settings::Manager::setBool("underwater effect", "Water", false); // shadows not supported @@ -487,13 +480,11 @@ namespace MWGui Settings::Manager::setBool("shaders", "Objects", true); // re-enable - if (MWRender::RenderingManager::waterShaderSupported()) - { - mWaterShaderButton->setEnabled(true); - mReflectObjectsButton->setEnabled(true); - mReflectActorsButton->setEnabled(true); - mReflectTerrainButton->setEnabled(true); - } + mReflectObjectsButton->setEnabled(true); + mReflectActorsButton->setEnabled(true); + mReflectTerrainButton->setEnabled(true); + mRefractionButton->setEnabled(true); + mUnderwaterButton->setEnabled(true); mShadowsEnabledButton->setEnabled(true); } diff --git a/files/materials/water.mat b/files/materials/water.mat index 7546606fc..372058f0a 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -1,5 +1,7 @@ material Water { + allow_fixed_function false + pass { emissive 1.0 1.0 1.0 @@ -44,7 +46,7 @@ material Water tex_address_mode border tex_border_colour 0.5 0.5 1.0 } - + // for simple_water texture_unit animatedTexture { From 6a8c532244c901d6de89487e57cf6c611e1f8cc4 Mon Sep 17 00:00:00 2001 From: greye Date: Sun, 24 Feb 2013 14:59:21 +0400 Subject: [PATCH 742/916] fix and unify object cell change update in mwrender --- apps/openmw/mwrender/actors.cpp | 12 ++++++------ apps/openmw/mwrender/actors.hpp | 2 +- apps/openmw/mwrender/objects.cpp | 6 +++--- apps/openmw/mwrender/objects.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 14 +++++--------- apps/openmw/mwrender/renderingmanager.hpp | 7 ++++--- apps/openmw/mwworld/worldimp.cpp | 3 ++- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 485e3a7ad..78521d0ce 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -149,10 +149,10 @@ Animation* Actors::getAnimation(const MWWorld::Ptr &ptr) return NULL; } -void Actors::updateObjectCell(const MWWorld::Ptr &ptr) +void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *node; - MWWorld::CellStore *newCell = ptr.getCell(); + MWWorld::CellStore *newCell = cur.getCell(); CellSceneNodeMap::const_iterator celliter = mCellSceneNodes.find(newCell); if(celliter != mCellSceneNodes.end()) @@ -162,15 +162,15 @@ void Actors::updateObjectCell(const MWWorld::Ptr &ptr) node = mMwRoot->createChildSceneNode(); mCellSceneNodes[newCell] = node; } - node->addChild(ptr.getRefData().getBaseNode()); + node->addChild(cur.getRefData().getBaseNode()); - PtrAnimationMap::iterator iter = mAllActors.find(ptr); + PtrAnimationMap::iterator iter = mAllActors.find(old); if(iter != mAllActors.end()) { Animation *anim = iter->second; mAllActors.erase(iter); - anim->updatePtr(ptr); - mAllActors[ptr] = anim; + anim->updatePtr(cur); + mAllActors[cur] = anim; } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index fc9fa4fbb..c89bfbaf5 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -42,7 +42,7 @@ namespace MWRender void update (float duration); /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &ptr); + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); Animation* getAnimation(const MWWorld::Ptr &ptr); }; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index fe81eb911..2bbb229a3 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -533,10 +533,10 @@ void Objects::rebuildStaticGeometry() } } -void Objects::updateObjectCell(const MWWorld::Ptr &ptr) +void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *node; - MWWorld::CellStore *newCell = ptr.getCell(); + MWWorld::CellStore *newCell = cur.getCell(); if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { node = mMwRoot->createChildSceneNode(); @@ -544,6 +544,6 @@ void Objects::updateObjectCell(const MWWorld::Ptr &ptr) } else { node = mCellSceneNodes[newCell]; } - node->addChild(ptr.getRefData().getBaseNode()); + node->addChild(cur.getRefData().getBaseNode()); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 283c05388..b7dd5a3b1 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -95,7 +95,7 @@ public: void rebuildStaticGeometry(); /// Updates containing cell for object rendering data - void updateObjectCell(const MWWorld::Ptr &ptr); + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 0b9730dea..5dd2b3773 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -302,23 +302,19 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot } void -RenderingManager::moveObjectToCell( - const MWWorld::Ptr& ptr, - const Ogre::Vector3& pos, - MWWorld::CellStore *store) +RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) { Ogre::SceneNode *child = - mRendering.getScene()->getSceneNode(ptr.getRefData().getHandle()); + mRendering.getScene()->getSceneNode(old.getRefData().getHandle()); Ogre::SceneNode *parent = child->getParentSceneNode(); parent->removeChild(child); - if (MWWorld::Class::get(ptr).isActor()) { - mActors.updateObjectCell(ptr); + if (MWWorld::Class::get(old).isActor()) { + mActors.updateObjectCell(old, cur); } else { - mObjects.updateObjectCell(ptr); + mObjects.updateObjectCell(old, cur); } - child->setPosition(pos); } void RenderingManager::update (float duration, bool paused) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b6c33f9c0..bdb5447e3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -123,9 +123,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setWaterHeight(const float height); void toggleWater(); - /// Moves object rendering part to proper container - /// \param store Cell the object was in previously (\a ptr has already been updated to the new cell). - void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::CellStore *store); + /// Updates object rendering after cell change + /// \param old Object reference in previous cell + /// \param cur Object reference in new cell + void updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur); void update (float duration, bool paused); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 71e956b6e..f723934be 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -770,7 +770,8 @@ namespace MWWorld MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); - mRendering->moveObjectToCell(copy, vec, currCell); + mRendering->updateObjectCell(ptr, copy); + MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); mechMgr->updateCell(copy); From 89d4c245e9b2a8b5fff0afa1494ec5417fe67331 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 03:30:33 -0800 Subject: [PATCH 743/916] Better calculate jump velocity The fatigue term isn't currently used correctly --- apps/openmw/mwclass/npc.cpp | 41 +++++++++++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 8 ++++++ apps/openmw/mwmechanics/character.cpp | 24 ++++++++++++---- apps/openmw/mwworld/class.cpp | 5 ++++ apps/openmw/mwworld/class.hpp | 3 ++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 642c7f645..12b40bfdc 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -71,6 +71,11 @@ namespace MWClass fMaxFlySpeed = gmst.find("fMaxFlySpeed"); fSwimRunBase = gmst.find("fSwimRunBase"); fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult"); + fJumpEncumbranceBase = gmst.find("fJumpEncumbranceBase"); + fJumpEncumbranceMultiplier = gmst.find("fJumpEncumbranceMultiplier"); + fJumpAcrobaticsBase = gmst.find("fJumpAcrobaticsBase"); + fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier"); + fJumpRunMultiplier = gmst.find("fJumpRunMultiplier"); // Added in Tribunal/Bloodmoon, may not exist fWereWolfRunMult = gmst.search("fWereWolfRunMult"); @@ -371,6 +376,37 @@ namespace MWClass return moveSpeed; } + float Npc::getJump(const MWWorld::Ptr &ptr) const + { + const CustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); + const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); + const float encumbranceTerm = fJumpEncumbranceBase->getFloat() + + fJumpEncumbranceMultiplier->getFloat() * + (Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); + + float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); + float b = 0.0f; + if(a > 50.0f) + { + b = a - 50.0f; + a = 50.0f; + } + + float x = fJumpAcrobaticsBase->getFloat() + + std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat()); + x += 3 * b * fJumpAcroMultiplier->getFloat(); + x += mageffects.get(MWMechanics::EffectKey(9/*jump*/)).mMagnitude * 64; + x *= encumbranceTerm; + + if(Npc::getStance(ptr, Run, false)) + x *= fJumpRunMultiplier->getFloat(); + x *= 1.25f;//fatigueTerm; + x -= -627.2/*gravity constant*/; + x /= 3; + + return x; + } + MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const { ensureCustomData (ptr); @@ -496,5 +532,10 @@ namespace MWClass const ESM::GameSetting *Npc::fMaxFlySpeed; const ESM::GameSetting *Npc::fSwimRunBase; const ESM::GameSetting *Npc::fSwimRunAthleticsMult; + const ESM::GameSetting *Npc::fJumpEncumbranceBase; + const ESM::GameSetting *Npc::fJumpEncumbranceMultiplier; + const ESM::GameSetting *Npc::fJumpAcrobaticsBase; + const ESM::GameSetting *Npc::fJumpAcroMultiplier; + const ESM::GameSetting *Npc::fJumpRunMultiplier; const ESM::GameSetting *Npc::fWereWolfRunMult; } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index a97e4c42e..f41edb0df 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -27,6 +27,11 @@ namespace MWClass static const ESM::GameSetting *fMaxFlySpeed; static const ESM::GameSetting *fSwimRunBase; static const ESM::GameSetting *fSwimRunAthleticsMult; + static const ESM::GameSetting *fJumpEncumbranceBase; + static const ESM::GameSetting *fJumpEncumbranceMultiplier; + static const ESM::GameSetting *fJumpAcrobaticsBase; + static const ESM::GameSetting *fJumpAcroMultiplier; + static const ESM::GameSetting *fJumpRunMultiplier; static const ESM::GameSetting *fWereWolfRunMult; public: @@ -81,6 +86,9 @@ namespace MWClass virtual float getSpeed (const MWWorld::Ptr& ptr) const; ///< Return movement speed. + virtual float getJump(const MWWorld::Ptr &ptr) const; + ///< Return jump velocity (not accounting for movement) + virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; ///< Return desired movement. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 37477932a..8f7929805 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -172,11 +172,25 @@ Ogre::Vector3 CharacterController::update(float duration) bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); speed = cls.getSpeed(mPtr); - // This jump is all kinds of wrong. The speed is incorrect, the state should be set to - // Jump, and X/Y movement should be disallowed except for the initial thrust (which would - // be carried by "physics" until landing). - if(onground) - movement.z += vec.z * (500.0f*duration); + /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except + * for the initial thrust (which would be carried by "physics" until landing). */ + if(onground && vec.z > 0.0f) + { + float x = cls.getJump(mPtr); + + if(vec.x == 0 && vec.y == 0) + movement.z += x*duration; + else + { + /* FIXME: this would be more correct if we were going into a jumping state, + * rather than normal walking/idle states. */ + //Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); + //movement += Ogre::Vector3(lat.x, lat.y, 1.0f) * x * 0.707f * duration; + movement.z += x * 0.707f * duration; + } + + //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult; + } if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c76019149..71b24b65d 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -122,6 +122,11 @@ namespace MWWorld return 0; } + float Class::getJump (const Ptr& ptr) const + { + return 0; + } + MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const { throw std::runtime_error ("movement settings not supported by class"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 07dcb8fe0..1a6a16ca0 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -140,6 +140,9 @@ namespace MWWorld virtual float getSpeed (const Ptr& ptr) const; ///< Return movement speed. + virtual float getJump(const MWWorld::Ptr &ptr) const; + ///< Return jump velocity (not accounting for movement) + virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; ///< Return desired movement. From 62c5568ed9138eb679f0427a2ea655af872303eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Sun, 24 Feb 2013 16:57:07 +0100 Subject: [PATCH 744/916] Fix for the loadingbar to resemble vanilla Morrowind. --- files/mygui/openmw_loading_screen.layout | 4 ++-- files/mygui/openmw_progress.skin.xml | 13 +++++++++++++ files/mygui/smallbars.png | Bin 246 -> 3205 bytes 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 6862702ca..4b6861151 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -6,12 +6,12 @@ - + - + diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index c4b94e28e..4666be221 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -17,6 +17,11 @@
+ + + + + @@ -51,4 +56,12 @@ + + + + + + + +
diff --git a/files/mygui/smallbars.png b/files/mygui/smallbars.png index a9ed572ef6dd53092f3e35dd1fc871a60686e91d..f938412c259c540d8e085a339fa0d94c4294a361 100644 GIT binary patch literal 3205 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 V+qrc3Ge{oT%#5rJt6*+1{{u-NeNq4b delta 212 zcmV;_04x868TJ8?7Z(}`0ssI2A5Ut+00001b5ch_0Itp)>5(B9e*gz`Nliru*#ZX- z6CpS#nr{FA0EkIMK~xyiZP3990znLg;Xh%(5~&##IK14YFH6+F=H0OkN?-L%E#W(hUno^d&x2M`?)6%mba5mg|}wqAOD zjaaLXgil6Y2Ck=DGTNi*9(IC(f}_*`XaN-7J;m0Vu(X6{noP6(|JxT0PCY1eTX63H O0000 Date: Sun, 24 Feb 2013 16:57:40 +0100 Subject: [PATCH 745/916] Prettier repeated borders. --- files/mygui/openmw_hud_box.skin.xml | 88 +++++++++++++++-------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index ce231e5bb..464b6343a 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -2,76 +2,78 @@ - - - + + + + - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + - - - + + + + - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - From 2e6c63d9cd255f45a7e6ec8b1c78bc7a652954e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 17:18:22 +0100 Subject: [PATCH 746/916] Disable specular on NIF's --- components/nifogre/ogre_nif_loader.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c3bbc141b..27926b7c4 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -575,9 +575,17 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String { ambient = m->data.ambient; diffuse = m->data.diffuse; - specular = m->data.specular; emissive = m->data.emissive; - glossiness = m->data.glossiness; + + + // Vanilla does not handle specular. TODO: Add an engine (or ESX file) configuration option + // to re-enable specular for future mods. Will also need to specify light specular colors somewhere. + // Also, not sure if glossiness value here is actually correct. OGRE expects 0-255 value, not sure what range this one is. + //glossiness = m->data.glossiness; + //specular = m->data.specular; + glossiness = 0; + specular = Ogre::Vector3(0,0,0); + alpha = m->data.alpha; } From 7ea1f6a02a06e83a153ff85c7f3b5ab210c37ca7 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 00:23:10 -0800 Subject: [PATCH 747/916] fixes for using FFMPEG on windows --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 4 ++++ cmake/FindFFmpeg.cmake | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 00530a962..54df45ff4 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -153,6 +153,10 @@ void FFmpeg_Decoder::open(const std::string &fname) try { + for(size_t j = 0;j < mFormatCtx->nb_streams;j++) + if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) + mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; + if(avformat_find_stream_info(mFormatCtx, NULL) < 0) fail("Failed to find stream info in "+fname); diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index c80203a25..4147590d6 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -68,6 +68,7 @@ macro(find_component _component _pkgconfig _library _header) find_path(${_component}_INCLUDE_DIRS ${_header} HINTS + ${FFMPEGSDK_INC} ${PC_LIB${_component}_INCLUDEDIR} ${PC_LIB${_component}_INCLUDE_DIRS} PATH_SUFFIXES @@ -76,6 +77,7 @@ macro(find_component _component _pkgconfig _library _header) find_library(${_component}_LIBRARIES NAMES ${_library} HINTS + ${FFMPEGSDK_LIB} ${PC_LIB${_component}_LIBDIR} ${PC_LIB${_component}_LIBRARY_DIRS} ) @@ -97,6 +99,12 @@ endmacro() # Check for cached results. If there are skip the costly part. if (NOT FFMPEG_LIBRARIES) + set (FFMPEGSDK ENV${FFMPEG_HOME}) + if (FFMPEGSDK) + set (FFMPEGSDK_INC "${FFMPEGSDK}/include") + set (FFMPEGSDK_LIB "${FFMPEGSDK}/lib") + endif () + # Check for all possible component. find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h) find_component(AVFORMAT libavformat avformat libavformat/avformat.h) From 1ae2d3c6abd06cb76b151067c88a0b5d3a9090a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 19:00:06 +0100 Subject: [PATCH 748/916] For light objects without an AttachLight bone, attach the light to the center of the object instead of the origin. --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwrender/objects.cpp | 17 ++++++++++++++--- apps/openmw/mwrender/objects.hpp | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 9d0fe298b..c23e4b833 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -38,7 +38,7 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); else - objects.insertLight(ptr, NULL); + objects.insertLight(ptr, NULL, Ogre::Vector3(0,0,0)); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index c51cafc0e..06ddcb225 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -49,6 +49,12 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) node->detachObject (object); mRenderer.getScene()->destroyMovableObject (object); } + + Ogre::Node::ChildNodeIterator it = node->getChildIterator (); + while (it.hasMoreElements ()) + { + clearSceneNode(static_cast(it.getNext ())); + } } void Objects::setMwRoot(Ogre::SceneNode* root) @@ -219,11 +225,11 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool if (light) { - insertLight(ptr, entities.mSkelBase); + insertLight(ptr, entities.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); } } -void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) +void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter) { Ogre::SceneNode* insert = mRenderer.getScene()->getSceneNode(ptr.getRefData().getHandle()); assert(insert); @@ -291,9 +297,14 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase) // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node if (skelBase && skelBase->getSkeleton ()->hasBone ("AttachLight")) + { skelBase->attachObjectToBone ("AttachLight", light); + } else - insert->attachObject(light); + { + Ogre::SceneNode* childNode = insert->createChildSceneNode (fallbackCenter); + childNode->attachObject(light); + } mLights.push_back(info); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 283c05388..1a4829d9f 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -74,7 +74,7 @@ public: ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); - void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter); void enableLights(); void disableLights(); From f1a33093922a8f16a05e98af5b86c05eed9743f6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 24 Feb 2013 19:03:25 +0100 Subject: [PATCH 749/916] forgot to destroy child scene nodes --- apps/openmw/mwrender/objects.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 06ddcb225..53957152f 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -55,6 +55,7 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) { clearSceneNode(static_cast(it.getNext ())); } + node->removeAndDestroyAllChildren (); } void Objects::setMwRoot(Ogre::SceneNode* root) From e060713aa350b110c7b9e55f768c558048727d48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Feb 2013 20:37:29 +0100 Subject: [PATCH 750/916] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 8b396aad0..535e922ae 100644 --- a/credits.txt +++ b/credits.txt @@ -29,6 +29,7 @@ Jannik Heller (scrawl) Jason Hooks (jhooks) Joel Graff (graffy) Karl-Felix Glatzer (k1ll) +Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) From c60e858b0216c5d444db16b7c2eb5003f3886df1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 12:42:32 -0800 Subject: [PATCH 751/916] Create bones for NiTriShape nodes, and attach the entities to them Otherwise some models don't connect properly. NiTriShapes are more guaranteed to have unique names than their parent nodes. --- components/nifogre/ogre_nif_loader.cpp | 26 ++++++-------------------- components/nifogre/ogre_nif_loader.hpp | 8 ++------ 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index c52a73e1c..8c5d4dc5a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -303,9 +303,6 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { - if(node->recType == Nif::RC_NiTriShape) - return; - Ogre::Bone *bone; if(!skel->hasBone(node->name)) bone = skel->createBone(node->name); @@ -319,7 +316,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro bone->setBindingPose(); if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_NiTriShape /* Handled in the mesh loader */ )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); @@ -1073,8 +1071,7 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), (shape->parent ? shape->parent->name : shape->name), - shape->trafo.pos, shape->trafo.rotation, shape->trafo.scale)); + meshes.push_back(MeshInfo(mesh->getName(), shape->name)); } const Nif::NiNode *ninode = dynamic_cast(node); @@ -1108,8 +1105,7 @@ public: mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), (node->parent ? node->parent->name : node->name), - node->trafo.pos, node->trafo.rotation, node->trafo.scale)); + meshes.push_back(MeshInfo(mesh->getName(), node->name)); } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; @@ -1190,12 +1186,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, parentNode->attachObject(entity); } else if(entity != entitylist.mSkelBase) - { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - tag->setPosition(meshes[i].mPos); - tag->setOrientation(meshes[i].mRot); - tag->setScale(Ogre::Vector3(meshes[i].mScale)); - } + entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); } } else @@ -1248,12 +1239,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen else { if(entity->getMesh()->getName().find(filter) != std::string::npos) - { - Ogre::TagPoint *tag = entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - tag->setPosition(meshes[i].mPos); - tag->setOrientation(meshes[i].mRot); - tag->setScale(Ogre::Vector3(meshes[i].mScale)); - } + entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); } } } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 0064defe2..7a7b0c5a1 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -53,13 +53,9 @@ struct EntityList { struct MeshInfo { std::string mMeshName; std::string mTargetNode; - Ogre::Vector3 mPos; - Ogre::Matrix3 mRot; - float mScale; - MeshInfo(const std::string &name, const std::string &target, - const Ogre::Vector3 &pos, const Ogre::Matrix3 &rot, float scale) - : mMeshName(name), mTargetNode(target), mPos(pos), mRot(rot), mScale(scale) + MeshInfo(const std::string &name, const std::string &target) + : mMeshName(name), mTargetNode(target) { } }; typedef std::vector MeshInfoList; From 5267d17408017e2f0be488de05aa4b683b7852a1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 14:14:08 -0800 Subject: [PATCH 752/916] Revert "forgot to destroy child scene nodes" This reverts commit f1a33093922a8f16a05e98af5b86c05eed9743f6. Unneeded. The caller already calls this which destroys the children recursively --- apps/openmw/mwrender/objects.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9e79f0256..76f38eefc 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -55,7 +55,6 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) { clearSceneNode(static_cast(it.getNext ())); } - node->removeAndDestroyAllChildren (); } void Objects::setMwRoot(Ogre::SceneNode* root) From 74b8095fc70dd66027aebe8da081cc9cf3aae21c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 14:43:20 -0800 Subject: [PATCH 753/916] Use default parameters where appropriate --- apps/openmw/mwclass/light.cpp | 2 +- apps/openmw/mwrender/objects.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index c23e4b833..200f6e2d4 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -38,7 +38,7 @@ namespace MWClass if (!model.empty()) objects.insertMesh(ptr, "meshes\\" + model, true); else - objects.insertLight(ptr, NULL, Ogre::Vector3(0,0,0)); + objects.insertLight(ptr); } void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index e0b53f906..580101464 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -74,7 +74,7 @@ public: ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); - void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre::Vector3 fallbackCenter); + void insertLight (const MWWorld::Ptr& ptr, Ogre::Entity *skelBase=0, Ogre::Vector3 fallbackCenter=Ogre::Vector3(0.0f)); void enableLights(); void disableLights(); From 17a0a201dfe0281a8600fe30742bcd3e77ce9722 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 00:56:04 +0100 Subject: [PATCH 754/916] Various fixes and changes to the settings handling --- apps/launcher/datafilespage.cpp | 35 ++++++--------------- apps/launcher/graphicspage.cpp | 2 +- apps/launcher/settings/gamesettings.cpp | 32 +++++++++++++++++-- apps/launcher/settings/launchersettings.cpp | 8 +++++ 4 files changed, 48 insertions(+), 29 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 60e377afb..a0df2fb82 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -19,23 +19,6 @@ #include "datafilespage.hpp" -#include -/** - * Workaround for problems with whitespaces in paths in older versions of Boost library - */ -#if (BOOST_VERSION <= 104600) -namespace boost -{ - - template<> - inline boost::filesystem::path lexical_cast(const std::string& arg) - { - return boost::filesystem::path(arg); - } - -} /* namespace boost */ -#endif /* (BOOST_VERSION <= 104600) */ - using namespace ESM; using namespace std; @@ -241,7 +224,7 @@ void DataFilesPage::setupDataFiles() mDataFilesModel->sort(3); QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); - QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); mProfilesComboBox->setCurrentIndex(-1); mProfilesComboBox->addItems(profiles); @@ -271,7 +254,7 @@ void DataFilesPage::setupDataFiles() void DataFilesPage::loadSettings() { - QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); if (profile.isEmpty()) return; @@ -299,10 +282,12 @@ void DataFilesPage::saveSettings() if (mDataFilesModel->rowCount() < 1) return; - QString profile = mLauncherSettings.value(QString("Profiles/CurrentProfile")); + QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); - if (profile.isEmpty()) - return; + if (profile.isEmpty()) { + profile = mProfilesComboBox->currentText(); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile); + } mLauncherSettings.remove(QString("Profiles/") + profile + QString("/master")); mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); @@ -539,9 +524,9 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre return; // Profile was deleted // Store the previous profile - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), previous); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), previous); saveSettings(); - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), current); loadSettings(); } @@ -552,7 +537,7 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre return; // Save the new profile name - mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), current); + mLauncherSettings.setValue(QString("Profiles/currentprofile"), current); saveSettings(); // Remove the old one diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 49002e87e..b5a00b14c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -196,7 +196,7 @@ void GraphicsPage::loadSettings() resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); - qDebug() << "resolution from file: " << resolution; + if (resIndex != -1) mResolutionComboBox->setCurrentIndex(resIndex); } diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index c08179acc..af78757b7 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -8,6 +8,23 @@ #include +#include +/** + * Workaround for problems with whitespaces in paths in older versions of Boost library + */ +#if (BOOST_VERSION <= 104600) +namespace boost +{ + + template<> + inline boost::filesystem::path lexical_cast(const std::string& arg) + { + return boost::filesystem::path(arg); + } + +} /* namespace boost */ +#endif /* (BOOST_VERSION <= 104600) */ + #include "gamesettings.hpp" GameSettings::GameSettings(Files::ConfigurationManager &cfg) @@ -93,6 +110,8 @@ bool GameSettings::readFile(QTextStream &stream) mSettings.remove(key); QStringList values = cache.values(key); + values.append(mSettings.values(key)); + if (!values.contains(value)) { cache.insertMulti(key, value); } @@ -125,9 +144,16 @@ bool GameSettings::writeFile(QTextStream &stream) continue; // Quote paths with spaces - if (i.key() == QLatin1String("data")) { - if (i.value().contains(" ")) { - stream << i.key() << "=\"" << i.value() << "\"\n"; + if (i.key() == QLatin1String("data") + || i.key() == QLatin1String("data-local") + || i.key() == QLatin1String("resources")) + { + if (i.value().contains(QChar(' '))) + { + QString stripped = i.value(); + stripped.remove(QChar('\"')); // Remove quotes + + stream << i.key() << "=\"" << stripped << "\"\n"; continue; } } diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index e9730c235..ee529d891 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -66,6 +66,7 @@ bool LauncherSettings::writeFile(QTextStream &stream) QString sectionPrefix; QRegExp sectionRe("([^/]+)/(.+)$"); QMap settings = SettingsBase::getSettings(); + qDebug() << "writing " << settings; QMapIterator i(settings); i.toBack(); @@ -81,6 +82,13 @@ bool LauncherSettings::writeFile(QTextStream &stream) key = sectionRe.cap(2); } + // Get rid of legacy settings + if (key.contains(QChar('\\'))) + continue; + + if (key == QLatin1String("CurrentProfile")) + continue; + if (sectionPrefix != prefix) { sectionPrefix = prefix; stream << "\n[" << prefix << "]\n"; From b1381ddd693995d4920a0e683b313ed46869bf6f Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Mon, 25 Feb 2013 04:12:41 +0400 Subject: [PATCH 755/916] Nif loader: workaround for missed textures in BB/BH Works for Better Bodies / Better Heads addons. --- components/nifogre/ogre_nif_loader.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index dfbc93ee9..0ee778df3 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -540,7 +540,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String Nif::NiSourceTexture *st = t->textures[0].texture.getPtr(); if (st->external) { - /* Bethesda at some at some point converted all their BSA + /* Bethesda at some point converted all their BSA * textures from tga to dds for increased load speed, but all * texture file name references were kept as .tga. */ @@ -559,6 +559,17 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) texName = path + st->filename; } + else if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + { + // workaround for Better Heads addon + size_t lastSlash = st->filename.rfind('\\'); + if (lastSlash != std::string::npos && lastSlash + 1 != st->filename.size()) { + texName = path + st->filename.substr(lastSlash + 1); + // workaround for Better Bodies addon + if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) + texName = st->filename; + } + } } else warn("Found internal texture, ignoring."); } From a0007325ad7a2d4eb1af4328fe7f185586340c62 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 01:22:14 +0100 Subject: [PATCH 756/916] Added a warning when stylesheet cannot be read and check if data paths contain masters/plugins --- apps/launcher/datafilespage.cpp | 4 +- apps/launcher/maindialog.cpp | 42 +++++++++++++++------ apps/launcher/settings/graphicssettings.cpp | 2 - apps/launcher/settings/launchersettings.cpp | 1 - apps/launcher/utils/checkablemessagebox.cpp | 1 - apps/launcher/utils/profilescombobox.cpp | 3 -- apps/launcher/utils/textinputdialog.cpp | 1 - 7 files changed, 33 insertions(+), 21 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index a0df2fb82..f8ccf3e83 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -226,8 +226,8 @@ void DataFilesPage::setupDataFiles() QStringList profiles = mLauncherSettings.subKeys(QString("Profiles/")); QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); - mProfilesComboBox->setCurrentIndex(-1); - mProfilesComboBox->addItems(profiles); + if (!profiles.isEmpty()) + mProfilesComboBox->addItems(profiles); // Add the current profile if empty if (mProfilesComboBox->findText(profile) == -1) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c03a31fd5..c1e70bb3f 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -78,10 +78,20 @@ MainDialog::MainDialog() file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string())); } - file.open(QFile::ReadOnly); - QString styleSheet = QLatin1String(file.readAll()); - qApp->setStyleSheet(styleSheet); - file.close(); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error opening Launcher stylesheet")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(QObject::tr("
Could not open %0 for reading

\ + Please make sure you have the right permissions \ + and try again.
").arg(file.fileName())); + msgBox.exec(); + } else { + QString styleSheet = QLatin1String(file.readAll()); + qApp->setStyleSheet(styleSheet); + file.close(); + } connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); @@ -261,7 +271,6 @@ bool MainDialog::showFirstRunDialog() // Add a new profile if (msgBox.isChecked()) { - qDebug() << "add a new profile"; mLauncherSettings.setValue(QString("Profiles/CurrentProfile"), QString("Imported")); mLauncherSettings.remove(QString("Profiles/Imported/master")); @@ -330,7 +339,7 @@ bool MainDialog::setupLauncherSettings() paths.append(userPath + QString("launcher.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; + qDebug() << "Loading config file:" << qPrintable(path); QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -366,7 +375,8 @@ bool MainDialog::setupGameSettings() paths.append(globalPath + QString("openmw.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; + qDebug() << "Loading config file:" << qPrintable(path); + QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -388,7 +398,19 @@ bool MainDialog::setupGameSettings() file.close(); } - if (mGameSettings.getDataDirs().isEmpty()) + QStringList dataDirs; + + // Check if the paths actually contain data files + foreach (const QString path, mGameSettings.getDataDirs()) { + QDir dir(path); + QStringList filters; + filters << "*.esp" << "*.esm"; + + if (!dir.entryList(filters).isEmpty()) + dataDirs.append(path); + } + + if (dataDirs.isEmpty()) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Error detecting Morrowind installation")); @@ -415,13 +437,11 @@ bool MainDialog::setupGameSettings() if (selectedFile.isEmpty()) return false; // Cancel was clicked; - qDebug() << selectedFile; QFileInfo info(selectedFile); // Add the new dir to the settings file and to the data dir container mGameSettings.setValue(QString("data"), info.absolutePath()); mGameSettings.addDataDir(info.absolutePath()); - } return true; @@ -454,7 +474,7 @@ bool MainDialog::setupGraphicsSettings() paths.append(userPath + QString("settings.cfg")); foreach (const QString &path, paths) { - qDebug() << "Loading: " << path; + qDebug() << "Loading config file:" << qPrintable(path); QFile file(path); if (file.exists()) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp index fd70917b5..a92477ebb 100644 --- a/apps/launcher/settings/graphicssettings.cpp +++ b/apps/launcher/settings/graphicssettings.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "graphicssettings.hpp" GraphicsSettings::GraphicsSettings() diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index ee529d891..1101a80b9 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -66,7 +66,6 @@ bool LauncherSettings::writeFile(QTextStream &stream) QString sectionPrefix; QRegExp sectionRe("([^/]+)/(.+)$"); QMap settings = SettingsBase::getSettings(); - qDebug() << "writing " << settings; QMapIterator i(settings); i.toBack(); diff --git a/apps/launcher/utils/checkablemessagebox.cpp b/apps/launcher/utils/checkablemessagebox.cpp index 990835594..41207a8de 100644 --- a/apps/launcher/utils/checkablemessagebox.cpp +++ b/apps/launcher/utils/checkablemessagebox.cpp @@ -29,7 +29,6 @@ #include "checkablemessagebox.hpp" -#include #include #include diff --git a/apps/launcher/utils/profilescombobox.cpp b/apps/launcher/utils/profilescombobox.cpp index 4c258dae6..c3ff953ae 100644 --- a/apps/launcher/utils/profilescombobox.cpp +++ b/apps/launcher/utils/profilescombobox.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include @@ -67,8 +66,6 @@ void ProfilesComboBox::slotEditingFinished() QString current = currentText(); QString previous = itemText(currentIndex()); - qDebug() << current << previous; - if (currentIndex() == -1) return; diff --git a/apps/launcher/utils/textinputdialog.cpp b/apps/launcher/utils/textinputdialog.cpp index 09b26ae75..011e51bf2 100644 --- a/apps/launcher/utils/textinputdialog.cpp +++ b/apps/launcher/utils/textinputdialog.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include From c4ebdc230c4ed65a6d6d6be7d212376ad4ba0ccf Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 01:28:13 +0100 Subject: [PATCH 757/916] Cleaned up strings and indentation --- apps/launcher/maindialog.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c1e70bb3f..c91ffa070 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -60,22 +60,22 @@ MainDialog::MainDialog() // Check if the font is installed if (!fonts.contains("EB Garamond")) { - QString font = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); - file.setFileName(font); + QString font = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf"); + file.setFileName(font); - if (!file.exists()) { - font = QString::fromStdString((mCfgMgr.getLocalPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); - } + if (!file.exists()) { + font = QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf"); + } - fontDatabase.addApplicationFont(font); + fontDatabase.addApplicationFont(font); } // Load the stylesheet - QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string()); + QString config = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/launcher.qss"); file.setFileName(config); if (!file.exists()) { - file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string())); + file.setFileName(QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("launcher.qss")); } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { From 53eb553c57b69f7ce7bbf36159348724bab184df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 24 Feb 2013 18:12:15 -0800 Subject: [PATCH 758/916] Be a little more aggressive when looking to skip generating a skeleton This is needed to handle the insane number of nodes and trishapes in in_prison_ship.nif, as Ogre has a 256-bone limit for skeletons. This is a bit sketchy, but it works. --- components/nifogre/ogre_nif_loader.cpp | 40 ++++++++++++++++---------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8c5d4dc5a..1582826b8 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -454,23 +454,33 @@ void loadResource(Ogre::Resource *resource) bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { - /* If the root node is a NiTriShape, or is a parent to only NiTriShapes, do - * not create a skeleton. */ - if(node->recType == Nif::RC_NiTriShape) - return false; - - if(node->recType == Nif::RC_NiNode) + /* We need to be a little aggressive here, since some NIFs have a crap-ton + * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: + * There are no bones used for skinning, there are no controllers on non- + * NiTriShape nodes, there are no nodes named "AttachLight", and the tree + * consists of NiNode, NiTriShape, and RootCollisionNode types only. + */ + if(!node->boneTrafo) { - bool alltrishapes = true; - const Nif::NiNode *ninode = static_cast(node); - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length() && alltrishapes;i++) - { - if(!children[i].empty() && children[i]->recType != Nif::RC_NiTriShape) - alltrishapes = false; - } - if(alltrishapes) + if(node->recType == Nif::RC_NiTriShape) return false; + if(node->controller.empty() && node->name != "AttachLight") + { + if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) + { + const Nif::NiNode *ninode = static_cast(node); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + { + if(createSkeleton(name, group, children[i].getPtr())) + return true; + } + } + return false; + } + } } Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); From dfe29db9cb7cb811c3aef9ceb0b977af2f3d4f35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 06:57:32 +0100 Subject: [PATCH 759/916] Fix bug #591: Don't allow opening new windows (main menu, console) if there's any modal widget active. Also made some windows modal that should be (character creation) --- apps/openmw/mwgui/birth.cpp | 4 ++-- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/class.cpp | 10 ++++++---- apps/openmw/mwgui/class.hpp | 8 ++++---- apps/openmw/mwgui/race.cpp | 4 +++- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/review.cpp | 3 ++- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/text_input.cpp | 3 ++- apps/openmw/mwgui/text_input.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++++ 11 files changed, 29 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index c53a68cf4..53e5c022d 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -25,7 +25,7 @@ bool sortBirthSigns(const std::pair& left, c } BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_birth.layout", parWindowManager) + : WindowModal("openmw_chargen_birth.layout", parWindowManager) { // Centre dialog center(); @@ -66,7 +66,7 @@ void BirthDialog::setNextButtonShow(bool shown) void BirthDialog::open() { - WindowBase::open(); + WindowModal::open(); updateBirths(); updateSpells(); } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index f16f92325..ad1c0b40f 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -10,7 +10,7 @@ namespace MWGui { - class BirthDialog : public WindowBase + class BirthDialog : public WindowModal { public: BirthDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 2eed21a52..f3bac898b 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -21,7 +21,7 @@ using namespace MWGui; /* GenerateClassResultDialog */ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_generate_class_result.layout", parWindowManager) + : WindowModal("openmw_chargen_generate_class_result.layout", parWindowManager) { // Centre dialog center(); @@ -68,7 +68,7 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) /* PickClassDialog */ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_class.layout", parWindowManager) + : WindowModal("openmw_chargen_class.layout", parWindowManager) { // Centre dialog center(); @@ -122,6 +122,7 @@ void PickClassDialog::setNextButtonShow(bool shown) void PickClassDialog::open() { + WindowModal::open (); updateClasses(); updateStats(); } @@ -276,7 +277,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) } InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_infobox.layout", parWindowManager) + : WindowModal("openmw_infobox.layout", parWindowManager) , mCurrentButton(-1) { getWidget(mTextBox, "TextBox"); @@ -327,6 +328,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons) void InfoBoxDialog::open() { + WindowModal::open(); // Fix layout layoutVertically(mTextBox, 4); layoutVertically(mButtonBar, 6); @@ -373,7 +375,7 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) /* CreateClassDialog */ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_create_class.layout", parWindowManager) + : WindowModal("openmw_chargen_create_class.layout", parWindowManager) , mSpecDialog(nullptr) , mAttribDialog(nullptr) , mSkillDialog(nullptr) diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index c7699b308..2662d94cc 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -12,7 +12,7 @@ namespace MWGui { - class InfoBoxDialog : public WindowBase + class InfoBoxDialog : public WindowModal { public: InfoBoxDialog(MWBase::WindowManager& parWindowManager); @@ -63,7 +63,7 @@ namespace MWGui ClassChoiceDialog(MWBase::WindowManager& parWindowManager); }; - class GenerateClassResultDialog : public WindowBase + class GenerateClassResultDialog : public WindowModal { public: GenerateClassResultDialog(MWBase::WindowManager& parWindowManager); @@ -90,7 +90,7 @@ namespace MWGui std::string mCurrentClassId; }; - class PickClassDialog : public WindowBase + class PickClassDialog : public WindowModal { public: PickClassDialog(MWBase::WindowManager& parWindowManager); @@ -238,7 +238,7 @@ namespace MWGui MyGUI::EditPtr mTextEdit; }; - class CreateClassDialog : public WindowBase + class CreateClassDialog : public WindowModal { public: CreateClassDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 054cce7b8..699c687ff 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -20,7 +20,7 @@ using namespace MWGui; using namespace Widgets; RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_race.layout", parWindowManager) + : WindowModal("openmw_chargen_race.layout", parWindowManager) , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) @@ -100,6 +100,8 @@ void RaceDialog::setNextButtonShow(bool shown) void RaceDialog::open() { + WindowModal::open(); + updateRaces(); updateSkills(); updateSpellPowers(); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index e0dc3306a..619556906 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -23,7 +23,7 @@ namespace MWGui namespace MWGui { - class RaceDialog : public WindowBase + class RaceDialog : public WindowModal { public: RaceDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 45adb5383..50dc26e42 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -23,7 +23,7 @@ using namespace Widgets; const int ReviewDialog::sLineHeight = 18; ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_chargen_review.layout", parWindowManager) + : WindowModal("openmw_chargen_review.layout", parWindowManager) , mLastPos(0) { // Centre dialog @@ -97,6 +97,7 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) void ReviewDialog::open() { + WindowModal::open(); updateSkillArea(); } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 2b0740234..aac609a64 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -17,7 +17,7 @@ Layout is defined by resources/mygui/openmw_chargen_review.layout. namespace MWGui { - class ReviewDialog : public WindowBase + class ReviewDialog : public WindowModal { public: enum Dialogs { diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 3dbe75165..c19394833 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -5,7 +5,7 @@ using namespace MWGui; TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_text_input.layout", parWindowManager) + : WindowModal("openmw_text_input.layout", parWindowManager) { // Centre dialog center(); @@ -39,6 +39,7 @@ void TextInputDialog::setTextLabel(const std::string &label) void TextInputDialog::open() { + WindowModal::open(); // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); } diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp index 848310369..649990281 100644 --- a/apps/openmw/mwgui/text_input.hpp +++ b/apps/openmw/mwgui/text_input.hpp @@ -13,7 +13,7 @@ namespace MWGui namespace MWGui { - class TextInputDialog : public WindowBase + class TextInputDialog : public WindowModal { public: TextInputDialog(MWBase::WindowManager& parWindowManager); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f1f88b9ae..0ce664c9b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -521,6 +521,9 @@ namespace MWInput void InputManager::toggleMainMenu() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) mWindows.popGuiMode(); else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) @@ -599,6 +602,9 @@ namespace MWInput void InputManager::toggleConsole() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + bool gameMode = !mWindows.isGuiMode(); // Switch to console mode no matter what mode we are currently From 151ecaad049411e42fde0de45e36b7dd2bee27aa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Feb 2013 10:32:38 +0100 Subject: [PATCH 760/916] workaround for garbage after an end statement --- components/compiler/fileparser.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/compiler/fileparser.cpp b/components/compiler/fileparser.cpp index 9b184f1ff..98be2d3d1 100644 --- a/components/compiler/fileparser.cpp +++ b/components/compiler/fileparser.cpp @@ -45,7 +45,10 @@ namespace Compiler reportWarning ("Names for script " + mName + " do not match", loc); mState = EndCompleteState; - return true; + return false; // we are stopping here, because there might be more garbage on the end line, + // that we must ignore. + // + /// \todo allow this workaround to be disabled for newer scripts } return Parser::parseName (name, loc, scanner); From 73d48a95f65ea68e1527ccd056362a855ae73619 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 16:31:48 +0100 Subject: [PATCH 761/916] Add message box when the player tries to move when being overencumbered. --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 25 +++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 +++--- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4f7435fad..81d7cb9fe 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -198,7 +198,7 @@ namespace MWBase virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; ///< Hides dialog and schedules dialog to be deleted. - virtual void messageBox (const std::string& message, const std::vector& buttons) = 0; + virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector()) = 0; virtual void enterPressed () = 0; virtual int readPressedButton() = 0; ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index fff627366..f57421137 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -188,7 +188,7 @@ namespace MWGui virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. - virtual void messageBox (const std::string& message, const std::vector& buttons); + virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector()); virtual void enterPressed (); virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 5a4c431f5..4a79f77b8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -21,6 +21,7 @@ #include "../engine.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -51,6 +52,7 @@ namespace MWInput , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) + , mOverencumberedMessageDelay(0.f) { Ogre::RenderWindow* window = ogre.getWindow (); size_t windowHnd; @@ -268,13 +270,16 @@ namespace MWInput // be done in the physics system. if (mControlSwitch["playercontrols"]) { + bool triedToMove = false; if (actionIsActive(A_MoveLeft)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setLeftRight (1); } @@ -283,11 +288,13 @@ namespace MWInput if (actionIsActive(A_MoveForward)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setForwardBackward (1); } else if (actionIsActive(A_MoveBackward)) { + triedToMove = true; mPlayer.setAutoMove (false); mPlayer.setForwardBackward (-1); } @@ -295,7 +302,10 @@ namespace MWInput mPlayer.setForwardBackward (0); if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) + { mPlayer.setUpDown (1); + triedToMove = true; + } else if (actionIsActive(A_Crouch)) mPlayer.setUpDown (-1); else @@ -306,6 +316,21 @@ namespace MWInput else mPlayer.setRunState(false); + // if player tried to start moving, but can't (due to being overencumbered), display a notification. + if (triedToMove) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); + mOverencumberedMessageDelay -= dt; + if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) + { + if (mOverencumberedMessageDelay <= 0) + { + MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); + mOverencumberedMessageDelay = 1.0; + } + } + } + if (mControlSwitch["playerviewswitch"]) { // work around preview mode toggle when pressing Alt+Tab diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 3af39911c..383fe3035 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -145,6 +145,8 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + float mOverencumberedMessageDelay; + float mMouseX; float mMouseY; int mMouseWheel; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index eee72f880..3cc3dcde3 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -491,8 +491,10 @@ namespace MWMechanics if(buying) x = buyTerm; else x = std::min(buyTerm, sellTerm); int offerPrice; - if (x < 1) offerPrice = int(x * basePrice); - if (x >= 1) offerPrice = basePrice + int((x - 1) * basePrice); + if (x < 1) + offerPrice = int(x * basePrice); + else + offerPrice = basePrice + int((x - 1) * basePrice); offerPrice = std::max(1, offerPrice); return offerPrice; } @@ -555,7 +557,7 @@ namespace MWMechanics float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); - float x,y; + float x,y = 0; float roll = static_cast (std::rand()) / RAND_MAX * 100; From 5d5d28c06ccabbbeae221a8eb4d906aeebc69b79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 07:43:56 -0800 Subject: [PATCH 762/916] Increase the ID cache to 40 Helps improve performance with Tribunal and Bloodmoon's scripts --- apps/openmw/mwworld/cells.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 59c62e37d..b912f5ccc 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -86,7 +86,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellS MWWorld::Cells::Cells (const MWWorld::ESMStore& store, std::vector& reader) : mStore (store), mReader (reader), - mIdCache (20, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable + mIdCache (40, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable mIdCacheIndex (0) {} From 88e8659a4959b9dcf0670796f75af6cac8b3b9f4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Feb 2013 16:52:31 +0100 Subject: [PATCH 763/916] minor cleanup --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3cc3dcde3..5ed3770fd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -557,7 +557,8 @@ namespace MWMechanics float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); - float x,y = 0; + float x = 0; + float y = 0; float roll = static_cast (std::rand()) / RAND_MAX * 100; From ff1ecb85c6cc1f02821024e1964abbf81633d545 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 08:22:57 -0800 Subject: [PATCH 764/916] Don't bother storing the shape name for the submesh name The submesh name Ogre has is completely useless to us --- components/nifogre/ogre_nif_loader.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1582826b8..826d247c6 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -763,7 +763,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mGroup; size_t mShapeIndex; std::string mMaterialName; - std::string mShapeName; void warn(const std::string &msg) { @@ -872,8 +871,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::VertexDeclaration *decl; int nextBuf = 0; - Ogre::SubMesh *sub = ((mShapeName.length() > 0) ? mesh->createSubMesh(mShapeName) : - mesh->createSubMesh()); + Ogre::SubMesh *sub = mesh->createSubMesh(); // Add vertices sub->useSharedVertices = false; @@ -1061,12 +1059,11 @@ public: if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = dynamic_cast(node); - mShapeName = shape->name; Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(mShapeName.length() > 0) - fullname += "@shape="+mShapeName; + if(shape->name.length() > 0) + fullname += "@shape="+shape->name; Misc::StringUtils::toLower(fullname); Ogre::MeshPtr mesh = meshMgr.getByName(fullname); From 355390429e68b7df609837f1acfbae631cdab5cc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 17:27:50 +0100 Subject: [PATCH 765/916] Fix World::isUnderwater to use dynamic waterlevel --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 10 +++++----- apps/openmw/mwworld/worldimp.hpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cc23e035e..eef844c76 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -288,7 +288,7 @@ namespace MWBase virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const = 0; + virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual void togglePOV() = 0; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5dd2b3773..559fc0115 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -381,7 +381,7 @@ void RenderingManager::update (float duration, bool paused) mWater->updateUnderwater( world->isUnderwater( - *world->getPlayer().getPlayer().getCell()->mCell, + world->getPlayer().getPlayer().getCell(), Ogre::Vector3(cam.x, -cam.z, cam.y)) ); mWater->update(duration); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be..eaee8f5a7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1411,16 +1411,16 @@ namespace MWWorld const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); if(actor) pos.z += actor->getHalfExtents().z * 1.5; - return isUnderwater(*object.getCell()->mCell, pos); + return isUnderwater(object.getCell(), pos); } bool - World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const + World::isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const { - if (!(cell.mData.mFlags & ESM::Cell::HasWater)) { + if (!(cell->mCell->mData.mFlags & ESM::Cell::HasWater)) { return false; } - return pos.z < cell.mWater; + return pos.z < cell->mWaterLevel; } bool World::isOnGround(const MWWorld::Ptr &ptr) const @@ -1448,7 +1448,7 @@ namespace MWWorld Ogre::Vector3 playerPos(refdata.getPosition().pos); const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(!physactor->getOnGround() || isUnderwater(*currentCell->mCell, playerPos)) + if(!physactor->getOnGround() || isUnderwater(currentCell, playerPos)) return 2; if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d347570fe..0ae81b33a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -316,7 +316,7 @@ namespace MWWorld virtual bool isFlying(const MWWorld::Ptr &ptr) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; - virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) const; + virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() { From 8aff033a0cc8bc7921e681b7bc2bf5d2a7b30599 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Feb 2013 18:29:11 +0100 Subject: [PATCH 766/916] Atmosphere no longer does "real" alpha blending to blend with the horizon, this is in preparation for proper underwater viewport BG / fog --- apps/openmw/mwrender/sky.cpp | 8 ++++++++ apps/openmw/mwrender/sky.hpp | 1 + files/materials/atmosphere.shader | 3 ++- files/materials/sky.mat | 1 - 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index ed34833e6..cda9ce6dd 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -255,6 +255,7 @@ void SkyManager::create() sh::Factory::getInstance().setSharedParameter ("nightFade", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); + sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); @@ -488,6 +489,13 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) weather.mSkyColor.r, weather.mSkyColor.g, weather.mSkyColor.b, weather.mSkyColor.a))); } + if (mFogColour != weather.mFogColor) + { + mFogColour = weather.mFogColor; + sh::Factory::getInstance().setSharedParameter ("horizonColour", sh::makeProperty(new sh::Vector4( + weather.mFogColor.r, weather.mFogColor.g, weather.mFogColor.b, weather.mFogColor.a))); + } + mCloudSpeed = weather.mCloudSpeed; if (weather.mNight && mStarsOpacity != weather.mNightFade) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 017eb4223..5a12b7ade 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -211,6 +211,7 @@ namespace MWRender float mStarsOpacity; Ogre::ColourValue mCloudColour; Ogre::ColourValue mSkyColour; + Ogre::ColourValue mFogColour; Ogre::Light* mLightning; diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 5d71d7c32..eb05c3e18 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -18,10 +18,11 @@ SH_BEGIN_PROGRAM shInput(float, alphaFade) shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) + shUniform(float4, horizonColour) @shSharedParameter(horizonColour, horizonColour) SH_START_PROGRAM { - shOutputColour(0) = atmosphereColour * float4(1,1,1,alphaFade); + shOutputColour(0) = alphaFade * atmosphereColour + (1.f - alphaFade) * horizonColour; } #endif diff --git a/files/materials/sky.mat b/files/materials/sky.mat index 4af90a170..e50aa51d8 100644 --- a/files/materials/sky.mat +++ b/files/materials/sky.mat @@ -59,7 +59,6 @@ material openmw_atmosphere polygon_mode_overrideable off - scene_blend alpha_blend depth_write off } } From 48271e49eccff7379911ae4abcaf00ba39a87125 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 09:57:34 -0800 Subject: [PATCH 767/916] Properly update the Ptr object in the mechanics manager when moving across cells --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwmechanics/activators.cpp | 6 ++++-- apps/openmw/mwmechanics/activators.hpp | 4 ++-- apps/openmw/mwmechanics/actors.cpp | 6 ++++-- apps/openmw/mwmechanics/actors.hpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 6 ++++++ apps/openmw/mwmechanics/character.hpp | 2 ++ apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 10 files changed, 26 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index cb9539ef6..b8733259f 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -43,7 +43,7 @@ namespace MWBase virtual void remove (const MWWorld::Ptr& ptr) = 0; ///< Deregister an object for management - virtual void updateCell(const MWWorld::Ptr &ptr) = 0; + virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) = 0; ///< Moves an object to a new cell virtual void drop (const MWWorld::CellStore *cellStore) = 0; diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 1a743cad5..b67fcb216 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -26,13 +26,15 @@ void Activators::removeActivator (const MWWorld::Ptr& ptr) mActivators.erase(iter); } -void Activators::updateActivatorCell(const MWWorld::Ptr &ptr) +void Activators::updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - PtrControllerMap::iterator iter = mActivators.find(ptr); + PtrControllerMap::iterator iter = mActivators.find(old); if(iter != mActivators.end()) { CharacterController ctrl = iter->second; mActivators.erase(iter); + + ctrl.updatePtr(ptr); mActivators.insert(std::make_pair(ptr, ctrl)); } } diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp index 0b9e984aa..137674a57 100644 --- a/apps/openmw/mwmechanics/activators.hpp +++ b/apps/openmw/mwmechanics/activators.hpp @@ -28,8 +28,8 @@ namespace MWMechanics void removeActivator (const MWWorld::Ptr& ptr); ///< Deregister an activator - void updateActivatorCell(const MWWorld::Ptr& ptr); - ///< Updates an activator with a new cell store + void updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an activator with a new Ptr void dropActivators (const MWWorld::CellStore *cellStore); ///< Deregister all activators in the given cell. diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a8c05f17e..9632bdf76 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -179,13 +179,15 @@ namespace MWMechanics mActors.erase(iter); } - void Actors::updateActorCell(const MWWorld::Ptr &ptr) + void Actors::updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - PtrControllerMap::iterator iter = mActors.find(ptr); + PtrControllerMap::iterator iter = mActors.find(old); if(iter != mActors.end()) { CharacterController ctrl = iter->second; mActors.erase(iter); + + ctrl.updatePtr(ptr); mActors.insert(std::make_pair(ptr, ctrl)); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index fbd787e83..fc4af8dd6 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -58,8 +58,8 @@ namespace MWMechanics /// /// \note Ignored, if \a ptr is not a registered actor. - void updateActorCell(const MWWorld::Ptr& ptr); - ///< Updates an actor with a new cell store + void updateActor(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an actor with a new Ptr void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 8f7929805..ae0114a35 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -131,6 +131,12 @@ CharacterController::~CharacterController() } +void CharacterController::updatePtr(const MWWorld::Ptr &ptr) +{ + mPtr = ptr; +} + + void CharacterController::markerEvent(float time, const std::string &evt) { if(evt == "stop") diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2465aea98..2b3c50864 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,6 +79,8 @@ public: CharacterController(const CharacterController &rhs); virtual ~CharacterController(); + void updatePtr(const MWWorld::Ptr &ptr); + Ogre::Vector3 update(float duration); void playGroup(const std::string &groupname, int mode, int count); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index eee72f880..a02b64e9d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -191,12 +191,12 @@ namespace MWMechanics mActivators.removeActivator(ptr); } - void MechanicsManager::updateCell(const MWWorld::Ptr &ptr) + void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.updateActivatorCell(ptr); + mActivators.updateActivator(old, ptr); else - mActors.updateActorCell(ptr); + mActors.updateActor(old, ptr); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 99010b7ff..5ad870571 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -48,7 +48,7 @@ namespace MWMechanics virtual void remove (const MWWorld::Ptr& ptr); ///< Deregister an object for management - virtual void updateCell(const MWWorld::Ptr &ptr); + virtual void updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr); ///< Moves an object to a new cell virtual void drop(const MWWorld::CellStore *cellStore); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be..c1725c00c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -773,7 +773,7 @@ namespace MWWorld mRendering->updateObjectCell(ptr, copy); MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager(); - mechMgr->updateCell(copy); + mechMgr->updateCell(ptr, copy); std::string script = MWWorld::Class::get(ptr).getScript(ptr); From 661fd73c6e1668a2c929f4ad5dd07afcaf83ec7a Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 25 Feb 2013 22:00:50 +0400 Subject: [PATCH 768/916] fix rotation for objects in inactive cells and forced vanity mode --- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f723934be..5eaa71b75 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -832,16 +832,16 @@ namespace MWWorld rot.y = Ogre::Degree(y).valueRadians(); rot.z = Ogre::Degree(z).valueRadians(); - float *objRot = ptr.getRefData().getPosition().rot; - if(ptr.getRefData().getBaseNode() == 0 || !mRendering->rotateObject(ptr, rot, adjust)) + if (mRendering->rotateObject(ptr, rot, adjust)) { - objRot[0] = (adjust ? objRot[0] + rot.x : rot.x), objRot[1] = (adjust ? objRot[1] + rot.y : rot.y), objRot[2] = (adjust ? objRot[2] + rot.z : rot.z); - return; - } + // rotate physically iff renderer confirm so + float *objRot = ptr.getRefData().getPosition().rot; + objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; - // do this after rendering rotated the object so it gets changed by Class->adjustRotation - objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; - mPhysics->rotateObject(ptr); + if (ptr.getRefData().getBaseNode() != 0) { + mPhysics->rotateObject(ptr); + } + } } void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) From 5f2c8970014a0c0719be67d9e2453f2323ce2731 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 10:29:48 -0800 Subject: [PATCH 769/916] Better handle which collision shapes to load --- components/nifbullet/bullet_nif_loader.cpp | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index a619bdda2..3d9c16ebb 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -155,6 +155,8 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // the flags we currently use, at least. flags |= node->flags; + isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); + // Marker objects: no collision /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) @@ -191,25 +193,26 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, } } - if(node->hasBounds) + if(!hasCollisionNode || isCollisionNode) { - cShape->boxTranslation = node->boundPos; - cShape->boxRotation = node->boundRot; - mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); - } + if(node->hasBounds) + { + cShape->boxTranslation = node->boundPos; + cShape->boxRotation = node->boundRot; + mBoundingBox = new btBoxShape(getbtVector(node->boundXYZ)); + } - if(node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) - { - cShape->mCollide = !(flags&0x800); - handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); + if(node->recType == Nif::RC_NiTriShape) + { + cShape->mCollide = !(flags&0x800); + handleNiTriShape(static_cast(node), flags, node->getWorldTransform(), raycastingOnly); + } } // For NiNodes, loop through children const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { - isCollisionNode = isCollisionNode || (node->recType == Nif::RC_RootCollisionNode); - const Nif::NodeList &list = ninode->children; for(size_t i = 0;i < list.length();i++) { From 9cd8dd39de31a902eafe118c9e293ee16f87218c Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 21:22:07 +0100 Subject: [PATCH 770/916] Make the launcher code conform to the coding standards and cleanup --- apps/launcher/datafilespage.cpp | 8 +++--- apps/launcher/graphicspage.cpp | 29 +++++++++++---------- apps/launcher/maindialog.cpp | 10 +++---- apps/launcher/playpage.cpp | 4 +-- apps/launcher/settings/gamesettings.cpp | 3 ++- apps/launcher/settings/graphicssettings.cpp | 4 +-- apps/launcher/settings/launchersettings.cpp | 4 +-- 7 files changed, 30 insertions(+), 32 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index f8ccf3e83..dd45c6602 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -1,3 +1,5 @@ +#include "datafilespage.hpp" + #include #include @@ -17,8 +19,6 @@ #include "utils/profilescombobox.hpp" #include "utils/textinputdialog.hpp" -#include "datafilespage.hpp" - using namespace ESM; using namespace std; @@ -216,9 +216,8 @@ void DataFilesPage::setupDataFiles() } QString dataLocal = mGameSettings.getDataLocal(); - if (!dataLocal.isEmpty()) { + if (!dataLocal.isEmpty()) mDataFilesModel->addFiles(dataLocal); - } // Sort by date accessed for now mDataFilesModel->sort(3); @@ -236,7 +235,6 @@ void DataFilesPage::setupDataFiles() if (mProfilesComboBox->findText(QString("Default")) == -1) mProfilesComboBox->addItem(QString("Default")); - if (profile.isEmpty() || profile == QLatin1String("Default")) { mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(QString("Default"))); } else { diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index b5a00b14c..741aacc9d 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,3 +1,5 @@ +#include "graphicspage.hpp" + #include #include @@ -10,7 +12,6 @@ #include #include "settings/graphicssettings.hpp" -#include "graphicspage.hpp" QString getAspect(int x, int y) { @@ -183,22 +184,22 @@ bool GraphicsPage::setupOgre() void GraphicsPage::loadSettings() { if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) - mVSyncCheckBox->setCheckState(Qt::Checked); + mVSyncCheckBox->setCheckState(Qt::Checked); - if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) - mFullScreenCheckBox->setCheckState(Qt::Checked); + if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) + mFullScreenCheckBox->setCheckState(Qt::Checked); - int aaIndex = mAntiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); - if (aaIndex != -1) - mAntiAliasingComboBox->setCurrentIndex(aaIndex); + int aaIndex = mAntiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); + if (aaIndex != -1) + mAntiAliasingComboBox->setCurrentIndex(aaIndex); - QString resolution = mGraphicsSettings.value(QString("Video/resolution x")); - resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); + QString resolution = mGraphicsSettings.value(QString("Video/resolution x")); + resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); - int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); + int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); - if (resIndex != -1) - mResolutionComboBox->setCurrentIndex(resIndex); + if (resIndex != -1) + mResolutionComboBox->setCurrentIndex(resIndex); } void GraphicsPage::saveSettings() @@ -215,8 +216,8 @@ void GraphicsPage::saveSettings() QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); if (resolutionRe.exactMatch(mResolutionComboBox->currentText().simplified())) { - mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); - mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); + mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); } } diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index c91ffa070..e69f134d2 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -1,9 +1,10 @@ +#include "maindialog.hpp" + #include #include "utils/checkablemessagebox.hpp" #include "utils/profilescombobox.hpp" -#include "maindialog.hpp" #include "playpage.hpp" #include "graphicspage.hpp" #include "datafilespage.hpp" @@ -74,9 +75,8 @@ MainDialog::MainDialog() QString config = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/launcher.qss"); file.setFileName(config); - if (!file.exists()) { + if (!file.exists()) file.setFileName(QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("launcher.qss")); - } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox msgBox; @@ -101,9 +101,8 @@ MainDialog::MainDialog() void MainDialog::createIcons() { - if (!QIcon::hasThemeIcon("document-new")) { + if (!QIcon::hasThemeIcon("document-new")) QIcon::setThemeName("tango"); - } // We create a fallback icon because the default fallback doesn't work QIcon graphicsIcon = QIcon(":/icons/tango/video-display.png"); @@ -733,4 +732,3 @@ bool MainDialog::startProgram(const QString &name, const QStringList &arguments, return true; } - diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index 1dbc1b9df..b082e2e2c 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -1,7 +1,7 @@ -#include - #include "playpage.hpp" +#include + PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { QWidget *playWidget = new QWidget(this); diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index af78757b7..56c08582f 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -1,3 +1,5 @@ +#include "gamesettings.hpp" + #include #include #include @@ -25,7 +27,6 @@ namespace boost } /* namespace boost */ #endif /* (BOOST_VERSION <= 104600) */ -#include "gamesettings.hpp" GameSettings::GameSettings(Files::ConfigurationManager &cfg) : mCfgMgr(cfg) diff --git a/apps/launcher/settings/graphicssettings.cpp b/apps/launcher/settings/graphicssettings.cpp index a92477ebb..0c5580091 100644 --- a/apps/launcher/settings/graphicssettings.cpp +++ b/apps/launcher/settings/graphicssettings.cpp @@ -1,10 +1,10 @@ +#include "graphicssettings.hpp" + #include #include #include #include -#include "graphicssettings.hpp" - GraphicsSettings::GraphicsSettings() { } diff --git a/apps/launcher/settings/launchersettings.cpp b/apps/launcher/settings/launchersettings.cpp index 1101a80b9..5d298e814 100644 --- a/apps/launcher/settings/launchersettings.cpp +++ b/apps/launcher/settings/launchersettings.cpp @@ -1,10 +1,10 @@ +#include "launchersettings.hpp" + #include #include #include #include -#include "launchersettings.hpp" - LauncherSettings::LauncherSettings() { } From b209b6a0e6cda392a3b7d78b12ecbdf7aa0838a9 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Mon, 25 Feb 2013 22:00:51 +0100 Subject: [PATCH 771/916] Added missing includes --- apps/launcher/settings/gamesettings.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index fa62872b0..6c296711f 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -1,14 +1,13 @@ #ifndef GAMESETTINGS_HPP #define GAMESETTINGS_HPP +#include +#include +#include #include #include -class QTextStream; -class QStringList; -class QString; - namespace Files { typedef std::vector PathContainer; struct ConfigurationManager;} From da575b181e4f6929b97d0255ccc8dec1f8362b6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 13:04:17 -0800 Subject: [PATCH 772/916] Use the correct GMST for the race menu --- apps/openmw/mwgui/race.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 699c687ff..71a4d1b3e 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -61,7 +61,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu4", "Race")); + setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu5", "Race")); getWidget(mRaceList, "RaceList"); mRaceList->setScrollVisible(true); mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); From 429bc23cf6c2bc763213cb6d1052ee398f374391 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 13:08:40 -0800 Subject: [PATCH 773/916] Convert the 0-1 glossiness parameter to 0-255 for shininess --- components/nifogre/ogre_nif_loader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 826d247c6..fd376045f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -683,7 +683,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); instance->setProperty ("specular", sh::makeProperty ( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); + new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); instance->setProperty ("emissive", sh::makeProperty ( new sh::Vector3(emissive.x, emissive.y, emissive.z))); From aefd12dfe046f08ab55160ff4248f8576ca8e406 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 15:44:59 -0800 Subject: [PATCH 774/916] Don't create meshes for collision shapes --- components/nifogre/ogre_nif_loader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index fd376045f..97b297238 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1031,6 +1031,10 @@ public: void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) { + // Do not create meshes for the collision shape (includes all children) + if(node->recType == Nif::RC_RootCollisionNode) + return; + flags |= node->flags; // Marker objects: just skip the entire node From a576e9e430b0feaf5c27bce36a3c3313b831a11a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 16:40:08 -0800 Subject: [PATCH 775/916] Set the race selection character preview in a valid (idle) pose. --- apps/openmw/mwrender/characterpreview.cpp | 6 ++++++ apps/openmw/mwrender/characterpreview.hpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 36cac2155..c32e9d1d6 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -161,6 +161,7 @@ namespace MWRender void RaceSelectionPreview::update(float angle) { + mAnimation->runAnimation(0.0f); mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); mNode->setVisible (true); @@ -175,4 +176,9 @@ namespace MWRender rebuild(); update(0); } + + void RaceSelectionPreview::onSetup () + { + mAnimation->play("idle", "start", "stop", false); + } } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index d07a03be7..cf1e25069 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -85,6 +85,8 @@ namespace MWRender public: RaceSelectionPreview(); + virtual void onSetup(); + void update(float angle); const ESM::NPC &getPrototype() const { From 955e2713a949e1d65d3c0f1bbf7975048960c8e0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 25 Feb 2013 17:29:32 -0800 Subject: [PATCH 776/916] Fix encumbrance term calculation --- apps/openmw/mwclass/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 12b40bfdc..c8c61e118 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -382,7 +382,7 @@ namespace MWClass const MWMechanics::MagicEffects &mageffects = npcdata->mCreatureStats.getMagicEffects(); const float encumbranceTerm = fJumpEncumbranceBase->getFloat() + fJumpEncumbranceMultiplier->getFloat() * - (Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); + (1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); float b = 0.0f; From a5451eb9d92164397a7dd5499976d77bbad436fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 08:30:06 +0100 Subject: [PATCH 777/916] Z-up conversion: terrain, objects --- apps/openmw/mwrender/renderingmanager.cpp | 3 +-- apps/openmw/mwrender/terrain.cpp | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 559fc0115..455e84f5e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -147,8 +147,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Morrowind uses, and it automagically makes everything work as it // should. SceneNode *rt = mRendering.getScene()->getRootSceneNode(); - mMwRoot = rt->createChildSceneNode("mwRoot"); - mMwRoot->pitch(Degree(-90)); + mMwRoot = rt; mObjects.setMwRoot(mMwRoot); mActors.setMwRoot(mMwRoot); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 2c2e9e6fc..47ee6f06f 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -26,7 +26,7 @@ namespace MWRender //---------------------------------------------------------------------------------------------- TerrainManager::TerrainManager(Ogre::SceneManager* mgr, RenderingManager* rend) : - mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) + mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Y, mLandSize, mWorldSize)), mRendering(rend) { mTerrainGlobals = OGRE_NEW TerrainGlobalOptions(); @@ -54,8 +54,8 @@ namespace MWRender mTerrainGlobals->setCompositeMapDistance(mWorldSize*2); mTerrainGroup.setOrigin(Vector3(mWorldSize/2, - 0, - -mWorldSize/2)); + mWorldSize/2, + 0)); Terrain::ImportData& importSettings = mTerrainGroup.getDefaultImportSettings(); From 3cb3ec91c065cd7ce4c229476b0e95a12cfe41f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 09:12:35 +0100 Subject: [PATCH 778/916] Z-up conversion: camera --- apps/openmw/mwrender/player.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 9ab8a7de3..1ac3b072f 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -113,11 +113,6 @@ namespace MWRender Ogre::Vector3 dir = mCamera->getRealDirection(); Ogre::Vector3 up = mCamera->getRealUp(); - Ogre::Real xch; - xch = pos.y, pos.y = -pos.z, pos.z = xch; - xch = dir.y, dir.y = -dir.z, dir.z = xch; - xch = up.y, up.y = -up.z, up.z = xch; - MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir, up); } @@ -323,10 +318,8 @@ namespace MWRender bool Player::getPosition(Ogre::Vector3 &player, Ogre::Vector3 &camera) { - float xch; mCamera->getParentSceneNode ()->needUpdate(true); camera = mCamera->getRealPosition(); - xch = camera.z, camera.z = camera.y, camera.y = -xch; player = mPlayerNode->getPosition(); return mFirstPersonView && !mVanity.enabled && !mPreviewMode; From 3ef952172d5a05133d94b9f3e6cf65a636eafa26 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 10:38:48 +0100 Subject: [PATCH 779/916] Z-up conversion: water, sky --- apps/openmw/mwrender/renderingmanager.cpp | 7 +++--- apps/openmw/mwrender/sky.cpp | 1 - apps/openmw/mwrender/water.cpp | 14 +++++------ files/materials/objects.shader | 12 ++++----- files/materials/terrain.shader | 16 ++++++------ files/materials/underwater.h | 6 ++--- files/materials/water.shader | 30 ++++++++++++----------- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 455e84f5e..b2d7fbff0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -365,7 +365,7 @@ void RenderingManager::update (float duration, bool paused) float *fpos = data.getPosition().pos; // only for LocalMap::updatePlayer() - Ogre::Vector3 pos(fpos[0], -fpos[2], -fpos[1]); + Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); Ogre::SceneNode *node = data.getBaseNode(); Ogre::Quaternion orient = @@ -381,7 +381,7 @@ void RenderingManager::update (float duration, bool paused) mWater->updateUnderwater( world->isUnderwater( world->getPlayer().getPlayer().getCell(), - Ogre::Vector3(cam.x, -cam.z, cam.y)) + cam) ); mWater->update(duration); } @@ -613,8 +613,7 @@ void RenderingManager::sunDisable() void RenderingManager::setSunDirection(const Ogre::Vector3& direction) { // direction * -1 (because 'direction' is camera to sun vector and not sun to camera), - // then convert from MW to ogre coordinates (swap y,z and make y negative) - if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.z, direction.y)); + if (mSun) mSun->setDirection(Vector3(-direction.x, -direction.y, -direction.z)); mSkyManager->setSunDirection(direction); } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 767f3c463..b747b0d9a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -236,7 +236,6 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) { mSceneMgr = pMwRoot->getCreator(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - mRootNode->pitch(Degree(-90)); // convert MW to ogre coordinates mRootNode->setInheritOrientation(false); } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e8f099640..e8ccbb2b4 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -42,9 +42,9 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mIsUnderwater = false; - mWaterPlane = Plane(Vector3::UNIT_Y, 0); + mWaterPlane = Plane(Vector3::UNIT_Z, 0); - MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z); + MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Y); mWater = mSceneManager->createEntity("water"); mWater->setVisibilityFlags(RV_Water); @@ -168,12 +168,12 @@ void Water::setHeight(const float height) { mTop = height; - mWaterPlane = Plane(Vector3::UNIT_Y, height); + mWaterPlane = Plane(Vector3::UNIT_Z, height); // small error due to reflection texture size & reflection distortion - mErrorPlane = Plane(Vector3::UNIT_Y, height - 5); + mErrorPlane = Plane(Vector3::UNIT_Z, height - 5); - mWaterNode->setPosition(0, height, 0); + mWaterNode->setPosition(0, 0, height); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); } @@ -199,7 +199,7 @@ Water::updateUnderwater(bool underwater) Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) { - return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2)); + return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), gridY * CELL_SIZE + (CELL_SIZE / 2), mTop); } void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) @@ -216,7 +216,7 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) mReflectionRenderActive = true; Vector3 pos = mCamera->getRealPosition(); - pos.y = mTop*2 - pos.y; + pos.z = mTop*2 - pos.z; mSky->setSkyPosition(pos); mReflectionCamera->enableReflection(mWaterPlane); } diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 25624351c..6adf7e3fa 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -225,9 +225,9 @@ float3 waterEyePos = float3(1,1,1); // NOTE: this calculation would be wrong for non-uniform scaling float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); + waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.y >= waterLevel || waterEnabled != 1.f) + if (worldPos.z >= waterLevel || waterEnabled != 1.f) caustics = float3(1,1,1); #endif @@ -269,7 +269,7 @@ #if UNDERWATER // regular fog only if fragment is above water - if (worldPos.y > waterLevel || waterEnabled != 1.f) + if (worldPos.z > waterLevel || waterEnabled != 1.f) #endif shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif @@ -278,7 +278,7 @@ shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); #if UNDERWATER - float fogAmount = (cameraPos.y > waterLevel) + float fogAmount = (cameraPos.z > waterLevel) ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); @@ -292,14 +292,14 @@ waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); float3 watercolour = ( gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; + watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; float darkness = VISIBILITY*2.0; darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; - float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; + float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index dee733263..e4f1cf091 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -88,8 +88,8 @@ float toMorph = -min(0, sign(uv1.y - lodMorph.y)); // morph - // this assumes XZ terrain alignment - worldPos.y += uv1.x * toMorph * lodMorph.x; + // this assumes XY terrain alignment + worldPos.z += uv1.x * toMorph * lodMorph.x; shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); @@ -233,9 +233,9 @@ float3 waterEyePos = float3(1,1,1); // NOTE: this calculation would be wrong for non-uniform scaling float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); + waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.y >= waterLevel) + if (worldPos.z >= waterLevel) caustics = float3(1,1,1); @@ -341,7 +341,7 @@ #if UNDERWATER // regular fog only if fragment is above water - if (worldPos.y > waterLevel) + if (worldPos.z > waterLevel) #endif shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif @@ -350,7 +350,7 @@ shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); #if UNDERWATER - float fogAmount = (cameraPos.y > waterLevel) + float fogAmount = (cameraPos.z > waterLevel) ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); @@ -365,14 +365,14 @@ float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; + watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; float darkness = VISIBILITY*2.0; darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; - float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; + float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); #endif diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 18052a98d..3b2540408 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -79,9 +79,9 @@ float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed) { - float waterDepth = shSaturate((waterEyePos.y - worldPos.y) / 50.0); + float waterDepth = shSaturate((waterEyePos.y - worldPos.z) / 50.0); - float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,1,0), waterLevel); + float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,0,1), waterLevel); ///\ todo clean this up float causticdepth = length(causticPos-worldPos.xyz); @@ -91,7 +91,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xzy * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); diff --git a/files/materials/water.shader b/files/materials/water.shader index 6bd277eab..b7fb60b6b 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -122,7 +122,7 @@ #define REFL_BUMP 0.08 // reflection distortion amount #define REFR_BUMP 0.06 // refraction distortion amount - #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering + #define SCATTER_AMOUNT 1.0 // amount of sunlight scattering #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering #define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction @@ -219,25 +219,27 @@ float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + - normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xzy; + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xyz; - normal = normalize(float3(normal.x * BUMP, normal.y, normal.z * BUMP)); + normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); + normal = float3(normal.x, normal.y, -normal.z); // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + - normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xzy; - lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y, lNormal.z * BUMP)); - + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xyz; + lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y * BUMP, lNormal.z)); + lNormal = float3(lNormal.x, lNormal.y, -lNormal.z); + float3 lVec = normalize(sunPosition.xyz); float3 vVec = normalize(position.xyz - cameraPos.xyz); - float isUnderwater = (cameraPos.y > 0) ? 0.0 : 1.0; + float isUnderwater = (cameraPos.z > 0) ? 0.0 : 1.0; // sunlight scattering - float3 pNormal = float3(0,1,0); + float3 pNormal = float3(0,0,1); float3 lR = reflect(lVec, lNormal); float3 llR = reflect(lVec, pNormal); @@ -246,13 +248,13 @@ float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*gammaCorrectRead(float3(1.0,0.4,0.0)), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); // fresnel - float ior = (cameraPos.y>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float ior = (cameraPos.z>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air float fresnel = fresnel_dielectric(-vVec, normal, ior); fresnel = shSaturate(fresnel); // reflection - float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb); + float3 reflection = gammaCorrectRead(shSample(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb); // refraction float3 R = reflect(vVec, normal); @@ -260,13 +262,13 @@ // check the depth at the refracted coords, and don't do any normal distortion for the refraction if the object to refract // is actually above the water (objectDepth < waterDepth) // this solves silhouettes around objects above the water - float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xz*REFR_BUMP)).x * far - depthPassthrough; + float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xy*REFR_BUMP)).x * far - depthPassthrough; float doRefraction = (refractDepth < 0) ? 0.f : 1.f; - float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(shoreFade * normal.xz*REFR_BUMP * doRefraction))*1.0).rgb); + float3 refraction = gammaCorrectRead(shSample(refractionMap, (screenCoords-(shoreFade * normal.xy*REFR_BUMP * doRefraction))*1.0).rgb); // brighten up the refraction underwater - refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction; + refraction = (cameraPos.z < 0) ? shSaturate(refraction * 1.5) : refraction; // specular float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); @@ -290,7 +292,7 @@ watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); float darkness = VISIBILITY*2.0; - darkness = clamp((cameraPos.y+darkness)/darkness,0.2,1.0); + darkness = clamp((cameraPos.z+darkness)/darkness,0.2,1.0); float fog = shSaturate(length(cameraPos.xyz-position.xyz) / VISIBILITY); From 5c0c5854e893b0aaa44ab3e936b0af24f9026cfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 12:01:10 +0100 Subject: [PATCH 780/916] Unrelated change: we always want the XAutoRepeat workaround, regardless of using exclusive input or not --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4a79f77b8..f7e1c8a84 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -87,10 +87,12 @@ namespace MWInput std::string("false"))); pl.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false"))); - pl.insert(std::make_pair(std::string("XAutoRepeatOn"), - std::string("true"))); #endif } +#if defined OIS_LINUX_PLATFORM + pl.insert(std::make_pair(std::string("XAutoRepeatOn"), + std::string("true"))); +#endif #if defined(__APPLE__) && !defined(__LP64__) // Give the application window focus to receive input events From 2e7bc1a368c730d7fc3e3691037c69476c0b5d0e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:39:10 +0100 Subject: [PATCH 781/916] Z-up conversion: local map, fix tcg --- apps/openmw/mwgui/map_window.cpp | 6 +- apps/openmw/mwrender/localmap.cpp | 80 +++++++++++------------ apps/openmw/mwrender/renderingmanager.cpp | 4 +- apps/openmw/mwrender/sky.cpp | 3 +- apps/openmw/mwworld/worldimp.cpp | 4 +- files/materials/water.shader | 4 +- libs/openengine/bullet/physic.cpp | 1 - 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 4e2ee517e..bbb2be648 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -88,7 +88,7 @@ void LocalMapBase::applyFogOfWar() + boost::lexical_cast(my); std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (mInterior ? (my-1) : -1*(my-1))); + + boost::lexical_cast(mCurY + (-1*(my-1))); MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; fog->setImageTexture(mFogOfWar ? ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" @@ -127,7 +127,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) { // map std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); + + boost::lexical_cast(y + (-1*(my-1))); std::string name = "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my); @@ -173,7 +173,7 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) } else { - Ogre::Vector2 position (marker.x, -marker.y); + Ogre::Vector2 position (marker.x, marker.y); MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index d878cb86e..b661c0795 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -28,9 +28,6 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mCellCamera = mRendering->getScene()->createCamera("CellCamera"); mCellCamera->setProjectionType(PT_ORTHOGRAPHIC); - // look down -y - const float sqrt0pt5 = 0.707106781; - mCellCamera->setOrientation(Quaternion(sqrt0pt5, -sqrt0pt5, 0, 0)); mCameraNode->attachObject(mCellCamera); } @@ -82,8 +79,8 @@ void LocalMap::saveFogOfWar(MWWorld::Ptr::CellStore* cell) } else { - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; // divide into segments @@ -107,6 +104,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) mInterior = false; mCameraRotNode->setOrientation(Quaternion::IDENTITY); + mCellCamera->setOrientation(Quaternion(Ogre::Math::Cos(Ogre::Degree(0)/2.f), 0, 0, -Ogre::Math::Sin(Ogre::Degree(0)/2.f))); int x = cell->mCell->getGridX(); int y = cell->mCell->getGridY(); @@ -115,7 +113,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) mCameraPosNode->setPosition(Vector3(0,0,0)); - render((x+0.5)*sSize, (-y-0.5)*sSize, -10000, 10000, sSize, sSize, name); + render((x+0.5)*sSize, (y+0.5)*sSize, -10000, 10000, sSize, sSize, name); } void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, @@ -124,40 +122,44 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mInterior = true; mBounds = bounds; - Vector2 z(mBounds.getMaximum().y, mBounds.getMinimum().y); + float zMin = mBounds.getMinimum().z; + float zMax = mBounds.getMaximum().z; const Vector2& north = MWBase::Environment::get().getWorld()->getNorthVector(cell); - Radian angle(std::atan2(-north.x, -north.y)); + Radian angle = Ogre::Math::ATan2 (north.x, north.y); mAngle = angle.valueRadians(); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, Math::Sin(angle/2.f), 0)); + + mCellCamera->setOrientation(Quaternion::IDENTITY); + mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, 0, -Math::Sin(angle/2.f))); // rotate the cell and merge the rotated corners to the bounding box - Vector2 _center(bounds.getCenter().x, bounds.getCenter().z); - Vector3 _c1 = bounds.getCorner(AxisAlignedBox::NEAR_LEFT_BOTTOM); - Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); - Vector3 _c3 = bounds.getCorner(AxisAlignedBox::NEAR_RIGHT_BOTTOM); - Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); - Vector2 c1(_c1.x, _c1.z); - Vector2 c2(_c2.x, _c2.z); - Vector2 c3(_c3.x, _c3.z); - Vector2 c4(_c4.x, _c4.z); + Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); + Vector3 _c1 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_BOTTOM); + Vector3 _c2 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_BOTTOM); + Vector3 _c3 = bounds.getCorner(AxisAlignedBox::FAR_LEFT_TOP); + Vector3 _c4 = bounds.getCorner(AxisAlignedBox::FAR_RIGHT_TOP); + + Vector2 c1(_c1.x, _c1.y); + Vector2 c2(_c2.x, _c2.y); + Vector2 c3(_c3.x, _c3.y); + Vector2 c4(_c4.x, _c4.y); c1 = rotatePoint(c1, _center, mAngle); c2 = rotatePoint(c2, _center, mAngle); c3 = rotatePoint(c3, _center, mAngle); c4 = rotatePoint(c4, _center, mAngle); - mBounds.merge(Vector3(c1.x, 0, c1.y)); - mBounds.merge(Vector3(c2.x, 0, c2.y)); - mBounds.merge(Vector3(c3.x, 0, c3.y)); - mBounds.merge(Vector3(c4.x, 0, c4.y)); + mBounds.merge(Vector3(c1.x, c1.y, 0)); + mBounds.merge(Vector3(c2.x, c2.y, 0)); + mBounds.merge(Vector3(c3.x, c3.y, 0)); + mBounds.merge(Vector3(c4.x, c4.y, 0)); - Vector2 center(mBounds.getCenter().x, mBounds.getCenter().z); + Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); - Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); + Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - mCameraPosNode->setPosition(Vector3(center.x, 0, center.y)); + mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); // divide into segments const int segsX = std::ceil( length.x / sSize ); @@ -172,7 +174,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, Vector2 start = min + Vector2(sSize*x,sSize*y); Vector2 newcenter = start + 4096; - render(newcenter.x - center.x, newcenter.y - center.y, z.y, z.x, sSize, sSize, + render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize, cell->mCell->mName + "_" + coordStr(x,y)); } } @@ -193,7 +195,7 @@ void LocalMap::render(const float x, const float y, mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); mRenderingManager->disableLights(); - mCameraNode->setPosition(Vector3(x, zhigh+100000, y)); + mCameraNode->setPosition(Vector3(x, y, 100000)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite @@ -272,15 +274,15 @@ void LocalMap::render(const float x, const float y, void LocalMap::getInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& nY, int& x, int& y) { - pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().z), mAngle); + pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), mAngle); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); x = std::ceil((pos.x - min.x)/sSize)-1; y = std::ceil((pos.y - min.y)/sSize)-1; nX = (pos.x - min.x - sSize*x)/sSize; - nY = (pos.y - min.y - sSize*y)/sSize; + nY = 1.0-(pos.y - min.y - sSize*y)/sSize; } bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interior) @@ -311,19 +313,19 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni int x,y; float u,v; - Vector2 pos(position.x, position.z); + Vector2 pos(position.x, position.y); if (mInterior) getInteriorMapPosition(pos, u,v, x,y); - Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).zAxis(); + Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); - Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().z); + Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); if (!mInterior) { x = std::ceil(pos.x / sSize)-1; - y = std::ceil(-pos.y / sSize)-1; + y = std::ceil(pos.y / sSize)-1; mCellX = x; mCellY = y; } @@ -337,7 +339,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { u = std::abs((pos.x - (sSize*x))/sSize); - v = 1-std::abs((pos.y + (sSize*y))/sSize); + v = 1.0-std::abs((pos.y - (sSize*y))/sSize); texBaseName = "Cell_"; } else @@ -346,15 +348,13 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } MWBase::Environment::get().getWindowManager()->setPlayerPos(u, v); - MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, -playerdirection.z); + MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); // explore radius (squared) const float sqrExploreRadius = (mInterior ? 0.01 : 0.09) * sFogOfWarResolution*sFogOfWarResolution; const float exploreRadius = (mInterior ? 0.1 : 0.3) * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) - int intExtMult = mInterior ? 1 : -1; // interior and exterior have reversed Y coordinates (interior: top to bottom) - // change the affected fog of war textures (in a 3x3 grid around the player) for (int mx = -1; mx<2; ++mx) { @@ -375,7 +375,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!affected) continue; - std::string texName = texBaseName + coordStr(x+mx,y+my*intExtMult); + std::string texName = texBaseName + coordStr(x+mx,y+my*-1); TexturePtr tex = TextureManager::getSingleton().getByName(texName+"_fog"); if (!tex.isNull()) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b2d7fbff0..fe8c5f57f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -368,8 +368,10 @@ void RenderingManager::update (float duration, bool paused) Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); Ogre::SceneNode *node = data.getBaseNode(); + //Ogre::Quaternion orient = + //node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); Ogre::Quaternion orient = - node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); +node->_getDerivedOrientation(); mLocalMap->updatePlayer(pos, orient); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index b747b0d9a..87790fab5 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -110,7 +110,7 @@ void BillboardObject::setPosition(const Vector3& pPosition) Vector3 BillboardObject::getPosition() const { Vector3 p = mNode->_getDerivedPosition() - mNode->getParentSceneNode()->_getDerivedPosition(); - return Vector3(p.x, -p.z, p.y); + return p; } void BillboardObject::setVisibilityFlags(int flags) @@ -390,7 +390,6 @@ void SkyManager::update(float duration) // increase the strength of the sun glare effect depending // on how directly the player is looking at the sun Vector3 sun = mSunGlare->getPosition(); - sun = Vector3(sun.x, sun.z, -sun.y); Vector3 cam = mCamera->getRealDirection(); const Degree angle = sun.angleBetween( cam ); float val = 1- (angle.valueDegrees() / 180.f); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index eaee8f5a7..ce39842b3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1228,8 +1228,8 @@ namespace MWWorld if (!ref) return Vector2(0, 1); Ogre::SceneNode* node = ref->mData.getBaseNode(); - Vector3 dir = node->_getDerivedOrientation().yAxis(); - Vector2 d = Vector2(dir.x, dir.z); + Vector3 dir = node->_getDerivedOrientation() * Ogre::Vector3(0,1,0); + Vector2 d = Vector2(dir.x, dir.y); return d; } diff --git a/files/materials/water.shader b/files/materials/water.shader index b7fb60b6b..a58a9c38b 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -122,7 +122,7 @@ #define REFL_BUMP 0.08 // reflection distortion amount #define REFR_BUMP 0.06 // refraction distortion amount - #define SCATTER_AMOUNT 1.0 // amount of sunlight scattering + #define SCATTER_AMOUNT 0.3 // amount of sunlight scattering #define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering #define SUN_EXT gammaCorrectRead(float3(0.45, 0.55, 0.68)) //sunlight extinction @@ -223,7 +223,7 @@ normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = float3(normal.x, normal.y, -normal.z); - + // normal for sunlight scattering float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 5d5749d5d..f993ce68e 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -193,7 +193,6 @@ namespace Physic if(!isDebugCreated) { Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - node->pitch(Ogre::Degree(-90)); mDebugDrawer = new BtOgre::DebugDrawer(node, dynamicsWorld); dynamicsWorld->setDebugDrawer(mDebugDrawer); isDebugCreated = true; From 284ba58e1e7372d74c80acd0f3f18d0b728ea901 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:52:01 +0100 Subject: [PATCH 782/916] Z-up conversion: global map, shader fix --- apps/openmw/mwgui/map_window.cpp | 2 +- apps/openmw/mwrender/globalmap.cpp | 2 +- files/materials/objects.shader | 2 +- files/materials/terrain.shader | 2 +- files/materials/underwater.h | 11 ++++++----- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index bbb2be648..34f246d8b 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -397,7 +397,7 @@ void MapWindow::globalMapUpdatePlayer () Ogre::Vector2 dir (orient.yAxis ().x, -orient.yAxis().z); float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.z, worldX, worldY); + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); worldX *= mGlobalMapRender->getWidth(); worldY *= mGlobalMapRender->getHeight(); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 072015f9a..055faaa1f 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -190,7 +190,7 @@ namespace MWRender { imageX = float(x / 8192.f - mMinX) / (mMaxX - mMinX + 1); - imageY = 1.f-float(-z / 8192.f - mMinY) / (mMaxY - mMinY + 1); + imageY = 1.f-float(z / 8192.f - mMinY) / (mMaxY - mMinY + 1); } void GlobalMap::cellTopLeftCornerToImageSpace(int x, int y, float& imageX, float& imageY) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 6adf7e3fa..0f1b3722f 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -296,7 +296,7 @@ float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); + darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index e4f1cf091..d8bc00c18 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -369,7 +369,7 @@ float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); + darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); watercolour *= darkness; float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 3b2540408..a760202fa 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -79,7 +79,7 @@ float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed) { - float waterDepth = shSaturate((waterEyePos.y - worldPos.z) / 50.0); + float waterDepth = shSaturate((waterEyePos.z - worldPos.z) / 50.0); float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,0,1), waterLevel); @@ -91,20 +91,21 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); float NdotL = max(dot(worldNormal.xyz, lightDirectionWS0.xyz),0.0); - float causticR = 1.0-perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticR = 1.0-perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; /// \todo sunFade // float3 caustics = clamp(pow(float3(causticR)*5.5,float3(5.5*causticdepth)),0.0,1.0)*NdotL*sunFade*causticdepth; float3 caustics = clamp(pow(float3(causticR,causticR,causticR)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)),0.0,1.0)*NdotL*causticdepth; - float causticG = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; - float causticB = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticG = 1.0-perturb(causticMap,causticPos.xy+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticB = 1.0-perturb(causticMap,causticPos.xy+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; From 341f9b96e2a589a86977d42b1856d147b4bc6f80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 13:53:23 +0100 Subject: [PATCH 783/916] Local map: restore zHigh --- apps/openmw/mwrender/localmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index b661c0795..601ee58e3 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -195,7 +195,7 @@ void LocalMap::render(const float x, const float y, mRendering->getScene()->setAmbientLight(ColourValue(1,1,1)); mRenderingManager->disableLights(); - mCameraNode->setPosition(Vector3(x, y, 100000)); + mCameraNode->setPosition(Vector3(x, y, zhigh+100000)); //mCellCamera->setFarClipDistance( (zhigh-zlow) * 1.1 ); mCellCamera->setFarClipDistance(0); // infinite From cc9b72b9b1f75f138bb38e1b095ed84a2b2f71a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:01:10 +0100 Subject: [PATCH 784/916] Removing some leftovers of mwRoot node --- apps/openmw/mwrender/actors.cpp | 8 ++++---- apps/openmw/mwrender/actors.hpp | 4 ++-- apps/openmw/mwrender/debugging.cpp | 8 ++++---- apps/openmw/mwrender/debugging.hpp | 4 ++-- apps/openmw/mwrender/objects.cpp | 20 ++++++++++---------- apps/openmw/mwrender/objects.hpp | 4 ++-- apps/openmw/mwrender/renderingmanager.cpp | 19 +++++++------------ apps/openmw/mwrender/renderingmanager.hpp | 5 +---- apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwrender/sky.hpp | 2 +- 10 files changed, 35 insertions(+), 43 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 78521d0ce..83c07737c 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -28,8 +28,8 @@ Actors::~Actors() } } -void Actors::setMwRoot(Ogre::SceneNode* root) -{ mMwRoot = root; } +void Actors::setRootNode(Ogre::SceneNode* root) +{ mRootNode = root; } void Actors::insertBegin(const MWWorld::Ptr &ptr) { @@ -40,7 +40,7 @@ void Actors::insertBegin(const MWWorld::Ptr &ptr) else { //Create the scenenode and put it in the map - cellnode = mMwRoot->createChildSceneNode(); + cellnode = mRootNode->createChildSceneNode(); mCellSceneNodes[ptr.getCell()] = cellnode; } @@ -159,7 +159,7 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) node = celliter->second; else { - node = mMwRoot->createChildSceneNode(); + node = mRootNode->createChildSceneNode(); mCellSceneNodes[newCell] = node; } node->addChild(cur.getRefData().getBaseNode()); diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index c89bfbaf5..75a18ba91 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -20,7 +20,7 @@ namespace MWRender typedef std::map PtrAnimationMap; OEngine::Render::OgreRenderer &mRend; - Ogre::SceneNode* mMwRoot; + Ogre::SceneNode* mRootNode; CellSceneNodeMap mCellSceneNodes; PtrAnimationMap mAllActors; @@ -29,7 +29,7 @@ namespace MWRender Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} ~Actors(); - void setMwRoot(Ogre::SceneNode* root); + void setRootNode(Ogre::SceneNode* root); void insertBegin (const MWWorld::Ptr& ptr); void insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv); void insertCreature (const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 2061b74d7..54f288bff 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -150,9 +150,9 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) return result; } -Debugging::Debugging(SceneNode *mwRoot, OEngine::Physic::PhysicEngine *engine) : - mMwRoot(mwRoot), mEngine(engine), - mSceneMgr(mwRoot->getCreator()), +Debugging::Debugging(SceneNode *root, OEngine::Physic::PhysicEngine *engine) : + mRootNode(root), mEngine(engine), + mSceneMgr(root->getCreator()), mPathgridEnabled(false), mInteriorPathgridNode(NULL), mPathGridRoot(NULL), mGridMatsCreated(false) @@ -208,7 +208,7 @@ void Debugging::togglePathgrid() createGridMaterials(); // add path grid meshes to already loaded cells - mPathGridRoot = mMwRoot->createChildSceneNode(); + mPathGridRoot = mRootNode->createChildSceneNode(); for(CellList::iterator it = mActiveCells.begin(); it != mActiveCells.end(); ++it) { enableCellPathgrid(*it); diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index 07e5f0a3f..6a4eef58f 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -54,7 +54,7 @@ namespace MWRender typedef std::vector CellList; CellList mActiveCells; - Ogre::SceneNode *mMwRoot; + Ogre::SceneNode *mRootNode; Ogre::SceneNode *mPathGridRoot; @@ -78,7 +78,7 @@ namespace MWRender Ogre::ManualObject *createPathgridLines(const ESM::Pathgrid *pathgrid); Ogre::ManualObject *createPathgridPoints(const ESM::Pathgrid *pathgrid); public: - Debugging(Ogre::SceneNode* mwRoot, OEngine::Physic::PhysicEngine *engine); + Debugging(Ogre::SceneNode* root, OEngine::Physic::PhysicEngine *engine); ~Debugging(); bool toggleRenderMode (int mode); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 76f38eefc..add781459 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -57,14 +57,14 @@ void Objects::clearSceneNode (Ogre::SceneNode *node) } } -void Objects::setMwRoot(Ogre::SceneNode* root) +void Objects::setRootNode(Ogre::SceneNode* root) { - mMwRoot = root; + mRootNode = root; } void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) { - Ogre::SceneNode* root = mMwRoot; + Ogre::SceneNode* root = mRootNode; Ogre::SceneNode* cellnode; if(mCellSceneNodes.find(ptr.getCell()) == mCellSceneNodes.end()) { @@ -390,9 +390,9 @@ void Objects::enableLights() std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(it->name)->setVisible(true); + mRootNode->getCreator()->getLight(it->name)->setVisible(true); ++it; } else @@ -405,9 +405,9 @@ void Objects::disableLights() std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(it->name)->setVisible(false); + mRootNode->getCreator()->getLight(it->name)->setVisible(false); ++it; } else @@ -460,9 +460,9 @@ void Objects::update(const float dt) std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(it->name)) + if (mRootNode->getCreator()->hasLight(it->name)) { - Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); + Ogre::Light* light = mRootNode->getCreator()->getLight(it->name); float brightness; float cycle_time; @@ -550,7 +550,7 @@ void Objects::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) MWWorld::CellStore *newCell = cur.getCell(); if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { - node = mMwRoot->createChildSceneNode(); + node = mRootNode->createChildSceneNode(); mCellSceneNodes[newCell] = node; } else { node = mCellSceneNodes[newCell]; diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 580101464..73e95a3c5 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -53,7 +53,7 @@ class Objects{ std::map mStaticGeometrySmall; std::map mBounds; std::vector mLights; - Ogre::SceneNode* mMwRoot; + Ogre::SceneNode* mRootNode; bool mIsStatic; static int uniqueID; @@ -90,7 +90,7 @@ public: void removeCell(MWWorld::CellStore* store); void buildStaticGeometry(MWWorld::CellStore &cell); - void setMwRoot(Ogre::SceneNode* root); + void setRootNode(Ogre::SceneNode* root); void rebuildStaticGeometry(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fe8c5f57f..fe3dc776d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -141,25 +141,20 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const applyCompositors(); - // Turn the entire scene (represented by the 'root' node) -90 - // degrees around the x axis. This makes Z go upwards, and Y go into - // the screen (when x is to the right.) This is the orientation that - // Morrowind uses, and it automagically makes everything work as it - // should. SceneNode *rt = mRendering.getScene()->getRootSceneNode(); - mMwRoot = rt; + mRootNode = rt; - mObjects.setMwRoot(mMwRoot); - mActors.setMwRoot(mMwRoot); + mObjects.setRootNode(mRootNode); + mActors.setRootNode(mRootNode); - Ogre::SceneNode *playerNode = mMwRoot->createChildSceneNode ("player"); + Ogre::SceneNode *playerNode = mRootNode->createChildSceneNode ("player"); mPlayer = new MWRender::Player (mRendering.getCamera(), playerNode); mShadows = new Shadows(&mRendering); mTerrainManager = new TerrainManager(mRendering.getScene(), this); - mSkyManager = new SkyManager(mMwRoot, mRendering.getCamera()); + mSkyManager = new SkyManager(mRootNode, mRendering.getCamera()); mOcclusionQuery = new OcclusionQuery(&mRendering, mSkyManager->getSunNode()); @@ -168,7 +163,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mSun = 0; - mDebugging = new Debugging(mMwRoot, engine); + mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); @@ -321,7 +316,7 @@ void RenderingManager::update (float duration, bool paused) Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { - orig.z += mPlayer->getHeight() * mMwRoot->getScale().z; + orig.z += mPlayer->getHeight() * mRootNode->getScale().z; btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index bdb5447e3..53c63cfed 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -228,10 +228,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::ColourValue mAmbientColor; Ogre::Light* mSun; - /// Root node for all objects added to the scene. This is rotated so - /// that the OGRE coordinate system matches that used internally in - /// Morrowind. - Ogre::SceneNode *mMwRoot; + Ogre::SceneNode *mRootNode; OEngine::Physic::PhysicEngine* mPhysicsEngine; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 87790fab5..062079693 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -203,7 +203,7 @@ unsigned int Moon::getPhaseInt() const return 0; } -SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) +SkyManager::SkyManager (SceneNode* root, Camera* pCamera) : mHour(0.0f) , mDay(0) , mMonth(0) @@ -234,7 +234,7 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) , mCloudAnimationTimer(0.f) , mMoonRed(false) { - mSceneMgr = pMwRoot->getCreator(); + mSceneMgr = root->getCreator(); mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); mRootNode->setInheritOrientation(false); } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 52fd7b4aa..feaba3d96 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -112,7 +112,7 @@ namespace MWRender class SkyManager { public: - SkyManager(Ogre::SceneNode* pMwRoot, Ogre::Camera* pCamera); + SkyManager(Ogre::SceneNode* root, Ogre::Camera* pCamera); ~SkyManager(); void update(float duration); From cd68012498881544eb00b9f902ab3bc9ef1bd1e5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:28:35 +0100 Subject: [PATCH 785/916] Z-up conversion: raycasts --- apps/openmw/mwworld/physicssystem.cpp | 14 ++++++-------- apps/openmw/mwworld/worldimp.cpp | 11 +++++------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 0c1f58048..65cbc1164 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -264,9 +264,8 @@ namespace MWWorld Ogre::Vector3 to = ray.getPoint(queryDistance); btVector3 _from, _to; - // OGRE to MW coordinates - _from = btVector3(from.x, -from.z, from.y); - _to = btVector3(to.x, -to.z, to.y); + _from = btVector3(from.x, from.y, from.z); + _to = btVector3(to.x, to.y, to.z); std::vector < std::pair > results; /* auto */ results = mEngine->rayTest2(_from,_to); @@ -287,7 +286,7 @@ namespace MWWorld Ray centerRay = mRender.getCamera()->getCameraToViewportRay( mRender.getViewport()->getWidth()/2, mRender.getViewport()->getHeight()/2); - btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); + btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z); return result; } @@ -295,7 +294,7 @@ namespace MWWorld { //get a ray pointing to the center of the viewport Ray centerRay = mRender.getCamera()->getCameraToViewportRay(mouseX, mouseY); - btVector3 result(centerRay.getPoint(extent).x,-centerRay.getPoint(extent).z,centerRay.getPoint(extent).y); + btVector3 result(centerRay.getPoint(extent).x,centerRay.getPoint(extent).y,centerRay.getPoint(extent).z); return result; } @@ -335,9 +334,8 @@ namespace MWWorld Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable btVector3 _from, _to; - // OGRE to MW coordinates - _from = btVector3(from.x, -from.z, from.y); - _to = btVector3(to.x, -to.z, to.y); + _from = btVector3(from.x, from.y, from.z); + _to = btVector3(to.x, to.y, to.z); std::pair result = mEngine->rayTest(_from, _to); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ce39842b3..24a1f8302 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1024,7 +1024,6 @@ namespace MWWorld // currently its here because we need to access the physics system float* p = mPlayer->getPlayer().getRefData().getPosition().pos; Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); - sun = Vector3(sun.x, -sun.z, sun.y); mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } @@ -1122,7 +1121,7 @@ namespace MWWorld } else p = mPhysics->getRayPoint(results.front().first); - Ogre::Vector3 pos(p.x(), p.z(), -p.y()); + Ogre::Vector3 pos(p.x(), p.y(), p.z()); Ogre::SceneNode* node = mFaced1.getRefData().getBaseNode(); //std::cout << "Num facing 1 : " << mFaced1Name << std::endl; @@ -1150,7 +1149,7 @@ namespace MWWorld } else p = mPhysics->getRayPoint(results.at (1).first); - Ogre::Vector3 pos(p.x(), p.z(), -p.y()); + Ogre::Vector3 pos(p.x(), p.y(), p.z()); Ogre::SceneNode* node1 = mFaced1.getRefData().getBaseNode(); Ogre::SceneNode* node2 = mFaced2.getRefData().getBaseNode(); @@ -1299,7 +1298,7 @@ namespace MWWorld if (isCellExterior()) { int cellX, cellY; - positionToIndex(result.second[0], -result.second[2], cellX, cellY); + positionToIndex(result.second[0], result.second[1], cellX, cellY); cell = mCells.getExterior(cellX, cellY); } else @@ -1307,8 +1306,8 @@ namespace MWWorld ESM::Position pos = getPlayer().getPlayer().getRefData().getPosition(); pos.pos[0] = result.second[0]; - pos.pos[1] = -result.second[2]; - pos.pos[2] = result.second[1]; + pos.pos[1] = result.second[1]; + pos.pos[2] = result.second[2]; Ptr dropped = copyObjectToCell(object, *cell, pos); PCDropped(dropped); From b9912a19e0ed585b041c33ce2861b224dea23369 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Feb 2013 14:31:30 +0100 Subject: [PATCH 786/916] Z-up conversion: fix player arrow direction on global map --- apps/openmw/mwgui/map_window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 34f246d8b..6f7f0eaab 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -394,7 +394,7 @@ void MapWindow::globalMapUpdatePlayer () { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, -orient.yAxis().z); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); float worldX, worldY; mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); From a7102c143f2f44701c95e2824ab93a459bb5d162 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Feb 2013 14:33:05 +0100 Subject: [PATCH 787/916] ESX variable type cleanup --- apps/openmw/mwworld/globals.cpp | 66 ++++++++++++++++----------------- components/esm/defs.hpp | 4 +- components/esm/loadglob.cpp | 4 +- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index f010661b9..8742dd892 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -21,21 +21,21 @@ namespace MWWorld Globals::Collection::const_iterator Globals::find (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); - - return iter; + + return iter; } Globals::Collection::iterator Globals::find (const std::string& name) { Collection::iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); - - return iter; + + return iter; } Globals::Globals (const MWWorld::ESMStore& store) @@ -46,44 +46,44 @@ namespace MWWorld { char type = ' '; Data value; - + switch (iter->mType) { case ESM::VT_Short: - + type = 's'; value.mShort = *reinterpret_cast ( &iter->mValue); break; - - case ESM::VT_Int: - + + case ESM::VT_Long: + type = 'l'; value.mLong = *reinterpret_cast ( &iter->mValue); break; - + case ESM::VT_Float: - + type = 'f'; value.mFloat = *reinterpret_cast ( &iter->mValue); break; - + default: - + throw std::runtime_error ("unsupported global variable type"); - } + } mVariables.insert (std::make_pair (iter->mId, std::make_pair (type, value))); } - + if (mVariables.find ("dayspassed")==mVariables.end()) { // vanilla Morrowind does not define dayspassed. Data value; value.mLong = 0; - + mVariables.insert (std::make_pair ("dayspassed", std::make_pair ('l', value))); } } @@ -91,31 +91,31 @@ namespace MWWorld const Globals::Data& Globals::operator[] (const std::string& name) const { Collection::const_iterator iter = find (name); - + return iter->second.second; } Globals::Data& Globals::operator[] (const std::string& name) { Collection::iterator iter = find (name); - + return iter->second.second; } - + void Globals::setInt (const std::string& name, int value) { Collection::iterator iter = find (name); - + switch (iter->second.first) { case 's': iter->second.second.mShort = value; break; case 'l': iter->second.second.mLong = value; break; case 'f': iter->second.second.mFloat = value; break; - + default: throw std::runtime_error ("unsupported global variable type"); } } - + void Globals::setFloat (const std::string& name, float value) { Collection::iterator iter = find (name); @@ -127,9 +127,9 @@ namespace MWWorld case 'f': iter->second.second.mFloat = value; break; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + int Globals::getInt (const std::string& name) const { Collection::const_iterator iter = find (name); @@ -141,13 +141,13 @@ namespace MWWorld case 'f': return iter->second.second.mFloat; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + float Globals::getFloat (const std::string& name) const { Collection::const_iterator iter = find (name); - + switch (iter->second.first) { case 's': return iter->second.second.mShort; @@ -155,16 +155,16 @@ namespace MWWorld case 'f': return iter->second.second.mFloat; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + char Globals::getType (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) return ' '; - + return iter->second.first; } } diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index aa870f925..143d90034 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -13,9 +13,9 @@ enum VarType { VT_Unknown, VT_None, - VT_Short, + VT_Short, // stored as a float, kinda VT_Int, - VT_Long, + VT_Long, // stored as a float VT_Float, VT_String, VT_Ignored diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index ceaa86948..429c6ff1d 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -12,7 +12,7 @@ void Global::load(ESMReader &esm) if (tmp == "s") mType = VT_Short; else if (tmp == "l") - mType = VT_Int; + mType = VT_Long; else if (tmp == "f") mType = VT_Float; else @@ -30,7 +30,7 @@ void Global::save(ESMWriter &esm) esm.writeHNString("FNAM", "s"); break; - case VT_Int: + case VT_Long: esm.writeHNString("FNAM", "l"); break; From 1a43d86d9e33cb1a8351347d37eaeaedfebca47b Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 15:58:32 +0100 Subject: [PATCH 788/916] Close messages boxes with the activation key (Bug #589) --- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f7e1c8a84..5a6998d9e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -179,6 +179,11 @@ namespace MWInput case A_Activate: resetIdleTime(); activate(); + if( MWBase::Environment::get().getWindowManager()->isGuiMode() + && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) { + // Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button + MWBase::Environment::get().getWindowManager()->enterPressed(); + } break; case A_Journal: toggleJournal (); From b1ca719d61b4df9b5ebcfd58457640febbd7da51 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 16:37:59 +0100 Subject: [PATCH 789/916] Added click sound to OK button for message boxes --- apps/openmw/mwgui/messagebox.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 896ab3bb5..0ee042e32 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -1,6 +1,8 @@ #include #include "messagebox.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" using namespace MWGui; @@ -375,6 +377,7 @@ void InteractiveMessageBox::enterPressed() if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) { buttonActivated(*button); + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); break; } } From fb990b5e69d96865f490f5ea4f747ad64d571a51 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Feb 2013 17:08:34 +0100 Subject: [PATCH 790/916] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 535e922ae..027dc0986 100644 --- a/credits.txt +++ b/credits.txt @@ -34,6 +34,7 @@ lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) Marcin Hulist (Gohan) +Manuel Edelmann (vorenon) Michael Mc Donnell Michael Papageorgiou (werdanith) Nathan Jeffords (blunted2night) From cd99e9d952d9a2b2b3f24425e678a83a1c9dd73c Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 26 Feb 2013 17:28:39 +0100 Subject: [PATCH 791/916] Updated credits.txt and corrected license info in readme.txt --- credits.txt | 58 +++++++++++++++++++++++++++++++++++------------------ readme.txt | 2 +- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/credits.txt b/credits.txt index 027dc0986..6f7e72aa1 100644 --- a/credits.txt +++ b/credits.txt @@ -12,66 +12,74 @@ Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) Aleksandar Jovanov +Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) athile BrotherBrick -Chris Robinson +Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) Douglas Diniz (Dgdiniz) +Douglas Mencken (dougmencken) +Edmondo Tommasina (edmondo) Eduard Cot (trombonecot) Eli2 -Emanuel "potatoesmaster" Guével -gugus / gus +Emanuel Guével (potatoesmaster) +gugus/gus Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) Joel Graff (graffy) +Jordan Milne +Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) Lukasz Gromanowski (lgro) Marcin Hulist (Gohan) +Mark Siewert (mark76) Manuel Edelmann (vorenon) Michael Mc Donnell Michael Papageorgiou (werdanith) Nathan Jeffords (blunted2night) Nikolay Kasyanov (corristo) +Nolan Poe (nopoe) +Paul McElroy (Greendogo) Pieter van der Kloet (pvdk) +Radu-Marius Popovici (rpopovici) Roman Melnik (Kromgart) +Sandy Carter (bwrsandman) Sebastian Wick (swick) Sergey Shambir -Sylvain T. (Garvek) +Sylvain Thesnieres (Garvek) Tom Mason (wheybags) + Packagers: Alexander Olofsson (Ace) - Windows BrotherBrick - Ubuntu Linux -Edmondo Tommasina - Gentoo Linux +Edmondo Tommasina (edmondo) - Gentoo Linux +Julian Ospald (hasufell) - Gentoo Linux +Karl-Felix Glatzer (k1ll) - Linux Binaries Kenny Armstrong (artorius) - Fedora Linux Nikolay Kasyanov (corristo) - Mac OS X Sandy Carter (bwrsandman) - Arch Linux -Public Relations: -ElderTroll - Release Manager -sir_herrbatka - News Writer +Public Relations and Translations: +Julien Voisin (jvoisin/ap0) - French News Writer +Artem Kotsynyak (greye) - Russian News Writer +Pithorn - Chinese News Writer +sir_herrbatka - English/Polish News Writer WeirdSexy - Podcaster Website: -juanmnzsk8 - Spanish News Writer -Julien Voisin (jvoisin/ap0) - French News Writer -Kingpix - Italian News Writer Lukasz Gromanowski (lgro) - Website Administrator -Nikolay Kasyanov (corristo) - Russian News Writer -Okulo - Dutch News Writer -penguinroad - Indonesian News Writer Ryan Sardonic (Wry) - Wiki Editor -sir_herrbatka - Forum Admin/Polish News Writer -spyboot - German News Writer +sir_herrbatka - Forum Administrator Formula Research: @@ -87,20 +95,32 @@ Sadler Artwork: Necrod - OpenMW Logo -raevol - Wordpress Theme - +Mickey Lyle (raevol) - Wordpress Theme +Okulo - OpenMW Editor Icons Inactive Contributors: Ardekantur Armin Preiml +Carl Maxwell Diggory Hardy -Jan Borsodi +Dmitry Marakasov (AMDmi3) +ElderTroll +guidoj Jan-Peter Nilsson (peppe) +Jan Borsodi Josua Grawitter +juanmnzsk8 +Kingpix Lordrea +Michal Sciubidlo Nicolay Korslund +pchan3 +penguinroad +psi29a sergoz +spyboot Star-Demon +Thoronador Yuri Krupenin diff --git a/readme.txt b/readme.txt index 3124744c3..228278a91 100644 --- a/readme.txt +++ b/readme.txt @@ -9,7 +9,7 @@ Website: http://www.openmw.org Font Licenses: EBGaramond-Regular.ttf: OFL (see OFL.txt for more information) -VeraMono.ttf: custom (see Bitstream Vera License.txt for more information) +DejaVuLGCSansMono.ttf: custom (see DejaVu Font License.txt for more information) From 21f502e3ddf191d67ff5569ac846a01574dcedc5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Tue, 26 Feb 2013 09:36:56 -0800 Subject: [PATCH 792/916] properly handle potentially non 16 bit planar audio formats --- apps/openmw/mwsound/ffmpeg_decoder.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 54df45ff4..7e8751c59 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -134,6 +134,18 @@ size_t FFmpeg_Decoder::readAVAudioData(void *data, size_t length) return dec; } +static AVSampleFormat ffmpegNonPlanarSampleFormat (AVSampleFormat format) +{ + switch (format) + { + case AV_SAMPLE_FMT_U8P: return AV_SAMPLE_FMT_U8; + case AV_SAMPLE_FMT_S16P: return AV_SAMPLE_FMT_S16; + case AV_SAMPLE_FMT_S32P: return AV_SAMPLE_FMT_S32; + case AV_SAMPLE_FMT_FLTP: return AV_SAMPLE_FMT_FLT; + case AV_SAMPLE_FMT_DBLP: return AV_SAMPLE_FMT_DBL; + default:return format; + } +} void FFmpeg_Decoder::open(const std::string &fname) { @@ -153,10 +165,6 @@ void FFmpeg_Decoder::open(const std::string &fname) try { - for(size_t j = 0;j < mFormatCtx->nb_streams;j++) - if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) - mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; - if(avformat_find_stream_info(mFormatCtx, NULL) < 0) fail("Failed to find stream info in "+fname); @@ -164,7 +172,6 @@ void FFmpeg_Decoder::open(const std::string &fname) { if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - mFormatCtx->streams[j]->codec->request_sample_fmt = AV_SAMPLE_FMT_S16; mStream = &mFormatCtx->streams[j]; break; } @@ -172,6 +179,8 @@ void FFmpeg_Decoder::open(const std::string &fname) if(!mStream) fail("No audio streams in "+fname); + (*mStream)->codec->request_sample_fmt = ffmpegNonPlanarSampleFormat ((*mStream)->codec->sample_fmt); + AVCodec *codec = avcodec_find_decoder((*mStream)->codec->codec_id); if(!codec) { From ceafcc2ebbc4a86e4f5cbc6f188658a10fdc58b4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Feb 2013 10:19:33 -0800 Subject: [PATCH 793/916] Support float samples with ffmpeg Requires the AL_EXT_FLOAT32 extension in OpenAL --- apps/openmw/mwrender/videoplayer.cpp | 2 ++ apps/openmw/mwsound/ffmpeg_decoder.cpp | 2 ++ apps/openmw/mwsound/openal_output.cpp | 45 +++++++++++++++++++++++++ apps/openmw/mwsound/sound_decoder.hpp | 3 +- apps/openmw/mwsound/soundmanagerimp.cpp | 2 ++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index b71022504..a0dedb6bc 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -404,6 +404,8 @@ public: *type = MWSound::SampleType_UInt8; else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = MWSound::SampleType_Int16; + else if(mAVStream->codec->sample_fmt == AV_SAMPLE_FMT_FLT) + *type = MWSound::SampleType_Float32; else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name(mAVStream->codec->sample_fmt)); diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index 54df45ff4..8c857f4ea 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -224,6 +224,8 @@ void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * *type = SampleType_UInt8; else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_S16) *type = SampleType_Int16; + else if((*mStream)->codec->sample_fmt == AV_SAMPLE_FMT_FLT) + *type = SampleType_Float32; else fail(std::string("Unsupported sample format: ")+ av_get_sample_fmt_name((*mStream)->codec->sample_fmt)); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 67008e2bc..1dc5f9974 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -88,6 +88,51 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type) } } } + if(alIsExtensionPresent("AL_EXT_FLOAT32")) + { + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltfmtlist[] = { + { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 }, + { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 }, + }; + static const size_t fltfmtlistsize = sizeof(fltfmtlist)/sizeof(fltfmtlist[0]); + + for(size_t i = 0;i < fltfmtlistsize;i++) + { + if(fltfmtlist[i].chans == chans && fltfmtlist[i].type == type) + { + ALenum format = alGetEnumValue(fltfmtlist[i].name); + if(format != 0 && format != -1) + return format; + } + } + if(alIsExtensionPresent("AL_EXT_MCFORMATS")) + { + static const struct { + char name[32]; + ChannelConfig chans; + SampleType type; + } fltmcfmtlist[] = { + { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 }, + { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 }, + { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 }, + }; + static const size_t fltmcfmtlistsize = sizeof(fltmcfmtlist)/sizeof(fltmcfmtlist[0]); + + for(size_t i = 0;i < fltmcfmtlistsize;i++) + { + if(fltmcfmtlist[i].chans == chans && fltmcfmtlist[i].type == type) + { + ALenum format = alGetEnumValue(fltmcfmtlist[i].name); + if(format != 0 && format != -1) + return format; + } + } + } + } fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); return AL_NONE; diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp index 29d99e8fa..151b58036 100644 --- a/apps/openmw/mwsound/sound_decoder.hpp +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -9,7 +9,8 @@ namespace MWSound { enum SampleType { SampleType_UInt8, - SampleType_Int16 + SampleType_Int16, + SampleType_Float32 }; const char *getSampleTypeName(SampleType type); diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index c50290680..1b07dfe62 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -607,6 +607,7 @@ namespace MWSound { case SampleType_UInt8: return "U8"; case SampleType_Int16: return "S16"; + case SampleType_Float32: return "Float32"; } return "(unknown sample type)"; } @@ -638,6 +639,7 @@ namespace MWSound { case SampleType_UInt8: frames *= 1; break; case SampleType_Int16: frames *= 2; break; + case SampleType_Float32: frames *= 4; break; } return frames; } From 13c33c1613adce9e7bf5b81debfe4922f3412734 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 19:37:47 +0100 Subject: [PATCH 794/916] added missing click sound to main menu --- apps/openmw/mwgui/mainmenu.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 14309abc5..5402d3542 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -5,6 +5,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" namespace MWGui { @@ -65,6 +66,7 @@ namespace MWGui void MainMenu::onButtonClicked(MyGUI::Widget *sender) { + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); if (sender == mButtons["return"]) MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); else if (sender == mButtons["options"]) From 89cba3cf455109e661d7e3db2139a7873628cfa5 Mon Sep 17 00:00:00 2001 From: vorenon Date: Tue, 26 Feb 2013 19:52:51 +0100 Subject: [PATCH 795/916] Replaced ifs/elseifs with switch --- apps/openmw/mwgui/waitdialog.cpp | 65 ++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 2c74dd2fd..794a9ab55 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -95,31 +95,46 @@ namespace MWGui // http://www.uesp.net/wiki/Lore:Calendar std::string month; int m = MWBase::Environment::get().getWorld ()->getMonth (); - if (m == 0) - month = "#{sMonthMorningstar}"; - else if (m == 1) - month = "#{sMonthSunsdawn}"; - else if (m == 2) - month = "#{sMonthFirstseed}"; - else if (m == 3) - month = "#{sMonthRainshand}"; - else if (m == 4) - month = "#{sMonthSecondseed}"; - else if (m == 5) - month = "#{sMonthMidyear}"; - else if (m == 6) - month = "#{sMonthSunsheight}"; - else if (m == 7) - month = "#{sMonthLastseed}"; - else if (m == 8) - month = "#{sMonthHeartfire}"; - else if (m == 9) - month = "#{sMonthFrostfall}"; - else if (m == 10) - month = "#{sMonthSunsdusk}"; - else if (m == 11) - month = "#{sMonthEveningstar}"; - + switch (m) { + case 0: + month = "#{sMonthMorningstar}"; + break; + case 1: + month = "#{sMonthSunsdawn}"; + break; + case 2: + month = "#{sMonthFirstseed}"; + break; + case 3: + month = "#{sMonthRainshand}"; + break; + case 4: + month = "#{sMonthSecondseed}"; + break; + case 5: + month = "#{sMonthMidyear}"; + break; + case 6: + month = "#{sMonthSunsheight}"; + break; + case 7: + month = "#{sMonthLastseed}"; + break; + case 8: + month = "#{sMonthHeartfire}"; + break; + case 9: + month = "#{sMonthFrostfall}"; + break; + case 10: + month = "#{sMonthSunsdusk}"; + break; + case 11: + month = "#{sMonthEveningstar}"; + break; + default: + break; + } int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); bool pm = hour >= 12; if (hour >= 13) hour -= 12; From 6b86db6b6fa7ff0a5020a4d95baa0da6ee6e9567 Mon Sep 17 00:00:00 2001 From: pvdk Date: Tue, 26 Feb 2013 20:49:20 +0100 Subject: [PATCH 796/916] Forgot the release manager and added the license terms of EB Garamond --- credits.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/credits.txt b/credits.txt index 6f7e72aa1..d1e85c690 100644 --- a/credits.txt +++ b/credits.txt @@ -69,8 +69,9 @@ Sandy Carter (bwrsandman) - Arch Linux Public Relations and Translations: -Julien Voisin (jvoisin/ap0) - French News Writer Artem Kotsynyak (greye) - Russian News Writer +Julien Voisin (jvoisin/ap0) - French News Writer +Mickey Lyle (raevol) - Release Manager Pithorn - Chinese News Writer sir_herrbatka - English/Polish News Writer WeirdSexy - Podcaster @@ -138,7 +139,7 @@ Thanks to Kevin Ryan, for creating the icon used for the Data Files tab of the OpenMW Launcher. Thanks to Georg Duffner, -for the open-source EB Garamond fontface. +for his EB Garamond fontface, see OFL.txt for his license terms. Thanks to Dongle, for his Daedric fontface, see Daedric Font License.txt for his license terms. From 759b2e96bf77a97cc0f2c713c2700ba51024791c Mon Sep 17 00:00:00 2001 From: lazydev Date: Wed, 27 Feb 2013 01:37:40 +0400 Subject: [PATCH 797/916] fix for https://bugs.openmw.org/issues/577 --- components/esm/loadcell.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 7400fd026..92cb7d5ce 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -112,8 +112,8 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) // instead. if (mData.mFlags & QuasiEx) mRegion = esm.getHNOString("RGNN"); - else - esm.getHNT(mAmbi, "AMBI", 16); + else if (esm.isNextSub("AMBI")) + esm.getHT(mAmbi); } else { @@ -126,7 +126,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) if (esm.isNextSub("NAM0")) { esm.getHT(mNAM0); } - + // preload moved references while (esm.isNextSub("MVRF")) { CellRef ref; @@ -135,7 +135,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) MWWorld::Store &cStore = const_cast&>(store.get()); ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); - + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following // implementation when the oher implementation works as well. getNextRef(esm, ref); @@ -143,7 +143,7 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), (int(*)(int)) std::tolower); - + // Add data required to make reference appear in the correct cell. // We should not need to test for duplicates, as this part of the code is pre-cell merge. mMovedRefs.push_back(cMRef); @@ -186,7 +186,7 @@ void Cell::save(ESMWriter &esm) if (mMapColor != 0) esm.writeHNT("NAM5", mMapColor); } - + if (mNAM0 != 0) esm.writeHNT("NAM0", mNAM0); } @@ -226,7 +226,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNT(ref.mRefnum, "FRMR"); ref.mRefID = esm.getHNString("NAME"); - + // Identify references belonging to a parent file and adapt the ID accordingly. int local = (ref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; @@ -249,7 +249,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // missing ref.mScale = 1.0; esm.getHNOT(ref.mScale, "XSCL"); - + // TODO: support loading references from saves, there are tons of keys not recognized yet. // The following is just an incomplete list. if (esm.isNextSub("ACTN")) @@ -266,7 +266,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.skipHSub(); else if (esm.isNextSub("CRED")) // ??? esm.skipHSub(); - + ref.mOwner = esm.getHNOString("ANAM"); ref.mGlob = esm.getHNOString("BNAM"); ref.mSoul = esm.getHNOString("XSOL"); @@ -305,7 +305,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHNOT(ref.mFltv, "FLTV"); esm.getHNOT(ref.mPos, "DATA", 24); - + // Number of references in the cell? Maximum once in each cell, // but not always at the beginning, and not always right. In other // words, completely useless. @@ -318,7 +318,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) esm.getHT(ref.mNam0); //esm.getHNOT(NAM0, "NAM0"); } - + if (esm.isNextSub("DELE")) { esm.skipHSub(); ref.mDeleted = 2; // Deleted, will not respawn. @@ -333,7 +333,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) { esm.getHT(mref.mRefnum); esm.getHNOT(mref.mTarget, "CNDT"); - + // Identify references belonging to a parent file and adapt the ID accordingly. int local = (mref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; From b4b20622c670bb15b78ede194f4f57a99b9f36b2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 26 Feb 2013 15:24:20 -0800 Subject: [PATCH 798/916] Properly handle NiAlphaProperty values --- components/nifogre/ogre_nif_loader.cpp | 139 ++++++++++--------------- 1 file changed, 57 insertions(+), 82 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5b84807a4..5042f666a 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -492,49 +492,43 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; -// Conversion of blend / test mode from NIF -> OGRE. -// Not in use yet, so let's comment it out. -/* -static SceneBlendFactor getBlendFactor(int mode) +// Conversion of blend / test mode from NIF +static const char *getBlendFactor(int mode) { - switch(mode) + switch(mode) { - case 0: return SBF_ONE; - case 1: return SBF_ZERO; - case 2: return SBF_SOURCE_COLOUR; - case 3: return SBF_ONE_MINUS_SOURCE_COLOUR; - case 4: return SBF_DEST_COLOUR; - case 5: return SBF_ONE_MINUS_DEST_COLOUR; - case 6: return SBF_SOURCE_ALPHA; - case 7: return SBF_ONE_MINUS_SOURCE_ALPHA; - case 8: return SBF_DEST_ALPHA; - case 9: return SBF_ONE_MINUS_DEST_ALPHA; - // [Comment from Chris Robinson:] Can't handle this mode? :/ - // case 10: return SBF_SOURCE_ALPHA_SATURATE; - default: - return SBF_SOURCE_ALPHA; + case 0: return "one"; + case 1: return "zero"; + case 2: return "src_colour"; + case 3: return "one_minus_src_colour"; + case 4: return "dest_colour"; + case 5: return "one_minus_dest_colour"; + case 6: return "src_alpha"; + case 7: return "one_minus_src_alpha"; + case 8: return "dest_alpha"; + case 9: return "one_minus_dest_alpha"; + case 10: return "src_alpha_saturate"; } + std::cerr<< "Unexpected blend mode: "<data->colors.size() != 0); @@ -640,7 +634,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String if (a) { alphaFlags = a->flags; -// alphaTest = a->data.threshold; + alphaTest = a->data.threshold; } // Material @@ -674,6 +668,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, texName); boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); + boost::hash_combine(h, alphaTest); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -705,57 +700,37 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty ("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Add transparency if NiAlphaProperty was present - if (alphaFlags != -1) + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); + if (result.first) { - // The 237 alpha flags are by far the most common. Check - // NiAlphaProperty in nif/property.h if you need to decode - // other values. 237 basically means normal transparencly. - if (alphaFlags == 237) - { - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); - if (result.first) - { - instance->setProperty("alpha_rejection", - sh::makeProperty(new sh::StringValue("greater_equal " + boost::lexical_cast(result.second)))); - } - else - { - // Enable transparency - instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); - } - } - else - warn("Unhandled alpha setting for texture " + texName); + alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ + alphaTest = result.second; + } + + if((alphaFlags&1)) + { + std::string blend_mode; + blend_mode += getBlendFactor((alphaFlags>>1)&0xf); + blend_mode += " "; + blend_mode += getBlendFactor((alphaFlags>>5)&0xf); + + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); + instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); } else - instance->getMaterial ()->setShadowCasterMaterial ("openmw_shadowcaster_noalpha"); + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - // As of yet UNTESTED code from Chris: - /*pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); - pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); - pass->setDepthCheckEnabled(true); - - // Add transparency if NiAlphaProperty was present - if (alphaFlags != -1) + if((alphaFlags>>9)&1) { - std::cout << "Alpha flags set!" << endl; - if ((alphaFlags&1)) - { - pass->setDepthWriteEnabled(false); - pass->setSceneBlending(getBlendFactor((alphaFlags>>1)&0xf), - getBlendFactor((alphaFlags>>5)&0xf)); - } - else - pass->setDepthWriteEnabled(true); - - if ((alphaFlags>>9)&1) - pass->setAlphaRejectSettings(getTestMode((alphaFlags>>10)&0x7), - alphaTest); - - pass->setTransparentSortingEnabled(!((alphaFlags>>13)&1)); + std::string reject; + reject += getTestMode((alphaFlags>>10)&0x7); + reject += " "; + reject += Ogre::StringConverter::toString(alphaTest); + instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } -*/ + + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(((alphaFlags>>13)&1) ? + "off" : "on"))); return matname; } From f994b7d227bd2639882f5f8a1b525bff6db77c9f Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 27 Feb 2013 07:44:35 +0400 Subject: [PATCH 799/916] Prepare .desktop file for more systems This brings condition for .desktop file preparation in sync with condition for its installation. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6929850b5..dbab83690 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,7 +297,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg.install") -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") +if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") endif() From 9b0ac4e2998facb18cd7b055d8371893c5588f89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Feb 2013 09:20:42 +0100 Subject: [PATCH 800/916] NPCs / creatures can now emit ripples --- apps/openmw/mwrender/actors.cpp | 9 ++ apps/openmw/mwrender/actors.hpp | 7 +- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 127 ++++++++++++---------- apps/openmw/mwrender/renderingmanager.hpp | 9 ++ apps/openmw/mwrender/ripplesimulation.cpp | 89 +++++++++++---- apps/openmw/mwrender/ripplesimulation.hpp | 22 +++- apps/openmw/mwrender/water.cpp | 26 +++-- apps/openmw/mwrender/water.hpp | 12 +- 9 files changed, 205 insertions(+), 98 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 83c07737c..644d3613b 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -6,6 +6,8 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" +#include "../mwrender/renderingmanager.hpp" + #include "animation.hpp" #include "activatoranimation.hpp" #include "creatureanimation.hpp" @@ -72,6 +74,7 @@ void Actors::insertNPC(const MWWorld::Ptr& ptr, MWWorld::InventoryStore& inv) NpcAnimation* anim = new NpcAnimation(ptr, ptr.getRefData().getBaseNode(), inv, RV_Actors); delete mAllActors[ptr]; mAllActors[ptr] = anim; + mRendering->addWaterRippleEmitter (ptr); } void Actors::insertCreature (const MWWorld::Ptr& ptr) { @@ -79,6 +82,7 @@ void Actors::insertCreature (const MWWorld::Ptr& ptr) CreatureAnimation* anim = new CreatureAnimation(ptr); delete mAllActors[ptr]; mAllActors[ptr] = anim; + mRendering->addWaterRippleEmitter (ptr); } void Actors::insertActivator (const MWWorld::Ptr& ptr) { @@ -90,6 +94,8 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr) bool Actors::deleteObject (const MWWorld::Ptr& ptr) { + mRendering->removeWaterRippleEmitter (ptr); + delete mAllActors[ptr]; mAllActors.erase(ptr); @@ -120,6 +126,7 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) { if(iter->first.getCell() == store) { + mRendering->removeWaterRippleEmitter (iter->first); delete iter->second; mAllActors.erase(iter++); } @@ -172,6 +179,8 @@ void Actors::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr &cur) anim->updatePtr(cur); mAllActors[cur] = anim; } + + mRendering->updateWaterRippleEmitterPtr (old, cur); } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 75a18ba91..bba2d945c 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -13,6 +13,7 @@ namespace MWWorld namespace MWRender { class Animation; + class RenderingManager; class Actors { @@ -20,13 +21,17 @@ namespace MWRender typedef std::map PtrAnimationMap; OEngine::Render::OgreRenderer &mRend; + MWRender::RenderingManager* mRendering; Ogre::SceneNode* mRootNode; CellSceneNodeMap mCellSceneNodes; PtrAnimationMap mAllActors; public: - Actors(OEngine::Render::OgreRenderer& _rend): mRend(_rend) {} + Actors(OEngine::Render::OgreRenderer& _rend, MWRender::RenderingManager* rendering) + : mRend(_rend) + , mRendering(rendering) + {} ~Actors(); void setRootNode(Ogre::SceneNode* root); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 8cf4ff123..8460d67aa 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -32,7 +32,7 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mLight = mRendering->getScene()->createLight(); mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLight->setDirection (Ogre::Vector3(0.3, 0.3, -0.7)); mLight->setVisible (false); mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9ef705fde..943208a66 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -51,7 +51,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) : mRendering(_rend) , mObjects(mRendering) - , mActors(mRendering) + , mActors(mRendering, this) , mAmbientMode(0) , mSunEnabled(0) , mPhysicsEngine(engine) @@ -136,7 +136,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); - sh::Factory::getInstance ().setSharedParameter ("viewportBackground", sh::makeProperty (new sh::Vector3(0,0,0))); sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); @@ -173,6 +172,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); + mWater = new MWRender::Water(mRendering.getCamera(), this); + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -222,15 +223,12 @@ void RenderingManager::removeCell (MWWorld::Ptr::CellStore *store) void RenderingManager::removeWater () { - if(mWater){ - mWater->setActive(false); - } + mWater->setActive(false); } void RenderingManager::toggleWater() { - if (mWater) - mWater->toggle(); + mWater->toggle(); } void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) @@ -321,6 +319,20 @@ RenderingManager::updateObjectCell(const MWWorld::Ptr &old, const MWWorld::Ptr & void RenderingManager::update (float duration, bool paused) { + MWBase::World *world = MWBase::Environment::get().getWorld(); + + // player position + MWWorld::RefData &data = + MWBase::Environment::get() + .getWorld() + ->getPlayer() + .getPlayer() + .getRefData(); + float *_playerPos = data.getPosition().pos; + Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); + + Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); + Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -343,6 +355,17 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); + /* + if (world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)) + { + mFogColour = Ogre::ColourValue(0.18039, 0.23137, 0.25490); + mFogStart = 0; + mFogEnd = 1500; + } + */ + + applyFog(); + if(paused) { return; @@ -358,41 +381,21 @@ void RenderingManager::update (float duration, bool paused) mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); - MWWorld::RefData &data = - MWBase::Environment::get() - .getWorld() - ->getPlayer() - .getPlayer() - .getRefData(); - - float *fpos = data.getPosition().pos; - - // only for LocalMap::updatePlayer() - Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - Ogre::SceneNode *node = data.getBaseNode(); //Ogre::Quaternion orient = //node->convertLocalToWorldOrientation(node->_getDerivedOrientation()); Ogre::Quaternion orient = node->_getDerivedOrientation(); - mLocalMap->updatePlayer(pos, orient); + mLocalMap->updatePlayer(playerPos, orient); - if (mWater) { - Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); + mWater->updateUnderwater( + world->isUnderwater( + world->getPlayer().getPlayer().getCell(), + cam) + ); - MWBase::World *world = MWBase::Environment::get().getWorld(); - - mWater->updateUnderwater( - world->isUnderwater( - world->getPlayer().getPlayer().getCell(), - cam) - ); - - // MW to ogre coordinates - orig = Ogre::Vector3(orig.x, orig.z, -orig.y); - mWater->update(duration, orig); - } + mWater->update(duration, playerPos); } void RenderingManager::preRenderTargetUpdate(const RenderTargetEvent &evt) @@ -416,10 +419,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) || ((store->mCell->isExterior()) && !lands.search(store->mCell->getGridX(),store->mCell->getGridY()) )) // always use water, if the cell does not have land. { - if(mWater == 0) - mWater = new MWRender::Water(mRendering.getCamera(), this, store->mCell); - else - mWater->changeCell(store->mCell); + mWater->changeCell(store->mCell); mWater->setActive(true); } else @@ -428,8 +428,7 @@ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store) void RenderingManager::setWaterHeight(const float height) { - if (mWater) - mWater->setHeight(height); + mWater->setHeight(height); } void RenderingManager::skyEnable () @@ -521,24 +520,26 @@ void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) { + mFogColour = colour; float max = Settings::Manager::getFloat("max viewing distance", "Viewing distance"); - float low = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); - float high = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); - - mRendering.getScene()->setFog (FOG_LINEAR, colour, 0, low, high); - - mRendering.getCamera()->setFarClipDistance ( max / density ); - mRendering.getViewport()->setBackgroundColour (colour); - - if (mWater) - mWater->setViewportBackground (colour); - - sh::Factory::getInstance ().setSharedParameter ("viewportBackground", - sh::makeProperty (new sh::Vector3(colour.r, colour.g, colour.b))); + mFogStart = max / (density) * Settings::Manager::getFloat("fog start factor", "Viewing distance"); + mFogEnd = max / (density) * Settings::Manager::getFloat("fog end factor", "Viewing distance"); + mRendering.getCamera()->setFarClipDistance ( Settings::Manager::getFloat("max viewing distance", "Viewing distance") / density ); } +void RenderingManager::applyFog () +{ + mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); + + mRendering.getViewport()->setBackgroundColour (mFogColour); + + mWater->setViewportBackground (mFogColour); + + sh::Factory::getInstance ().setSharedParameter ("viewportBackground", + sh::makeProperty (new sh::Vector3(mFogColour.r, mFogColour.g, mFogColour.b))); +} void RenderingManager::setAmbientMode() { @@ -826,8 +827,7 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } - if (mWater) - mWater->processChangedSettings(settings); + mWater->processChangedSettings(settings); if (rebuild) mObjects.rebuildStaticGeometry(); @@ -902,6 +902,8 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) MWWorld::Class::get(ptr).getInventoryStore(ptr), RV_Actors ); mPlayer->setAnimation(anim); + mWater->removeEmitter (ptr); + mWater->addEmitter (ptr); } void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw) @@ -945,4 +947,19 @@ void RenderingManager::stopVideo() mVideoPlayer->stopVideo (); } +void RenderingManager::addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale, float force) +{ + mWater->addEmitter (ptr, scale, force); +} + +void RenderingManager::removeWaterRippleEmitter (const MWWorld::Ptr& ptr) +{ + mWater->removeEmitter (ptr); +} + +void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + mWater->updateEmitterPtr(old, ptr); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5d79f80aa..02d796fdd 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -163,6 +163,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void skySetMoonColour (bool red); void configureAmbient(MWWorld::CellStore &mCell); + void addWaterRippleEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeWaterRippleEmitter (const MWWorld::Ptr& ptr); + void updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + void requestMap (MWWorld::CellStore* cell); ///< request the local map for a cell @@ -204,6 +208,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList sh::Factory* mFactory; void setAmbientMode(); + void applyFog(); void setMenuTransparency(float val); @@ -234,6 +239,10 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::SceneNode *mRootNode; + Ogre::ColourValue mFogColour; + float mFogStart; + float mFogEnd; + OEngine::Physic::PhysicEngine* mPhysicsEngine; MWRender::Player *mPlayer; diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 6c9264b60..47fbc8ddf 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -7,6 +7,11 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" + namespace MWRender { @@ -21,8 +26,7 @@ RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) mRippleAreaLength(1000), mImpulseSize(20), mTexelOffset(0,0), - mFirstUpdate(true), - mLastPos(0,0) + mFirstUpdate(true) { Ogre::AxisAlignedBox aabInf; aabInf.setInfinite(); @@ -142,34 +146,39 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); } -void RippleSimulation::addImpulse(Ogre::Vector2 position, float scale, float force) -{ - // don't emit if there wasn't enough movement - /// \todo this should be done somewhere else, otherwise multiple emitters cannot be supported - if ((position - mLastPos).length () <= 2) - return; - - mLastPos = position; - - /// \todo scale, force - mImpulses.push(position); -} - void RippleSimulation::addImpulses() { mRectangle->setVisible(false); mImpulse->setVisible(true); - while (mImpulses.size()) + /// \todo it should be more efficient to render all emitters at once + for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) { - Ogre::Vector2 pos = mImpulses.front(); - pos -= mRippleCenter; - pos /= mRippleAreaLength; - float size = mImpulseSize / mRippleAreaLength; - mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); - mImpulses.pop(); + if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()) + { + // fetch a new ptr (to handle cell change etc) + // for non-player actors this is done in updateObjectCell + it->mPtr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); + } + float* _currentPos = it->mPtr.getRefData().getPosition().pos; + Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]); - mRenderTargets[1]->update(); + if ( (currentPos - it->mLastEmitPosition).length() > 2 + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), currentPos)) + { + it->mLastEmitPosition = currentPos; + + Ogre::Vector2 pos (currentPos.x, currentPos.y); + pos -= mRippleCenter; + pos /= mRippleAreaLength; + float size = mImpulseSize / mRippleAreaLength; + mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); + + // don't render if we are offscreen + if (pos.x - size >= 1.0 || pos.y+size <= -1.0 || pos.x+size <= -1.0 || pos.y-size >= 1.0) + continue; + mRenderTargets[1]->update(); + } } mImpulse->setVisible(false); @@ -216,5 +225,39 @@ void RippleSimulation::swapHeightMaps() mTextures[2] = tmp2; } +void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) +{ + Emitter newEmitter; + newEmitter.mPtr = ptr; + newEmitter.mScale = scale; + newEmitter.mForce = force; + newEmitter.mLastEmitPosition = Ogre::Vector3(0,0,0); + mEmitters.push_back (newEmitter); +} + +void RippleSimulation::removeEmitter (const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == ptr) + { + mEmitters.erase(it); + return; + } + } +} + +void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + for (std::vector::iterator it = mEmitters.begin(); it != mEmitters.end(); ++it) + { + if (it->mPtr == old) + { + it->mPtr = ptr; + return; + } + } +} + } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index 2f8cae24f..7e7eebc1c 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -4,6 +4,9 @@ #include #include #include +#include + +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -16,6 +19,14 @@ namespace Ogre namespace MWRender { +struct Emitter +{ + MWWorld::Ptr mPtr; + Ogre::Vector3 mLastEmitPosition; + float mScale; + float mForce; +}; + class RippleSimulation { public: @@ -24,9 +35,14 @@ public: void update(float dt, Ogre::Vector2 position); - void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); + /// adds an emitter, position will be tracked automatically + void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::Ptr& ptr); + void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); private: + std::vector mEmitters; + Ogre::RenderTexture* mRenderTargets[4]; Ogre::TexturePtr mTextures[4]; @@ -34,8 +50,6 @@ private: float mRippleAreaLength; float mImpulseSize; - Ogre::Vector2 mLastPos; - bool mFirstUpdate; Ogre::Camera* mCamera; @@ -51,8 +65,6 @@ private: Ogre::Rectangle2D* mImpulse; - std::queue mImpulses; - void addImpulses(); void heightMapToNormalMap(); void waterSimulation(); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 7d6ca1a0d..d112e17b2 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -81,6 +81,7 @@ void CubeReflection::update () PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) : Reflection(sceneManager) , mSky(sky) + , mRenderActive(false) { mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); mSceneMgr->addRenderQueueListener(this); @@ -186,7 +187,7 @@ void PlaneReflection::setVisibilityMask (int flags) // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mActive(1), mToggled(1), @@ -202,7 +203,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mMaterial = MaterialManager::getSingleton().getByName("Water"); - mTop = cell->mWater; + mTop = 0; mIsUnderwater = false; @@ -216,10 +217,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - if(!(cell->mData.mFlags & cell->Interior)) - { - mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY)); - } mWaterNode->attachObject(mWater); applyRTT(); @@ -397,7 +394,7 @@ void Water::update(float dt, Ogre::Vector3 player) { //mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); } - mSimulation->update(dt, Ogre::Vector2(player.x, player.z)); + mSimulation->update(dt, Ogre::Vector2(player.x, player.y)); if (mReflection) mReflection->update(); @@ -499,10 +496,19 @@ void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& co } } -void Water::addImpulse (Vector2 position, float scale, float force) +void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) { - if (mSimulation) - mSimulation->addImpulse (position, scale, force); + mSimulation->addEmitter (ptr, scale, force); +} + +void Water::removeEmitter (const MWWorld::Ptr& ptr) +{ + mSimulation->removeEmitter (ptr); +} + +void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) +{ + mSimulation->updateEmitterPtr(old, ptr); } } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index eb7d98f5d..ddf6ef7ab 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -11,9 +11,12 @@ #include #include +#include + + #include "renderconst.hpp" -#include +#include "../mwworld/ptr.hpp" namespace Ogre { @@ -138,7 +141,7 @@ namespace MWRender { RippleSimulation* mSimulation; public: - Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell); + Water (Ogre::Camera *camera, RenderingManager* rend); ~Water(); void setActive(bool active); @@ -146,7 +149,10 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); - void addImpulse (Ogre::Vector2 position, float scale = 1.f, float force = 1.f); + /// adds an emitter, position will be tracked automatically using its scene node + void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); + void removeEmitter (const MWWorld::Ptr& ptr); + void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); void setViewportBackground(const Ogre::ColourValue& bg); From 0bc4c3556ae9f9c10e9197fb1ce18aab49a824c1 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 27 Feb 2013 15:58:01 +0100 Subject: [PATCH 801/916] Fix dialogue gender filter --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 09bb0ddc4..6f9d8b42f 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -289,7 +289,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con case SelectWrapper::Function_PcGender: - return player.get()->mBase->mFlags & ESM::NPC::Female ? 0 : 1; + return player.get()->mBase->isMale() ? 0 : 1; case SelectWrapper::Function_PcClothingModifier: { From 8966e88050a167e1bd6f40bcfd1376bdabc13ba4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Feb 2013 16:07:15 +0100 Subject: [PATCH 802/916] Fix shadows --- files/materials/objects.shader | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index d8498b831..88ca2d152 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -32,8 +32,11 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) +#if (VIEWPROJ_FIX) || (SHADOWS) + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif + #if VIEWPROJ_FIX - shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) shUniform(float4, vpRow2Fix) @shSharedParameter(vpRow2Fix, vpRow2Fix) shUniform(float4x4, vpMatrix) @shAutoConstant(vpMatrix, viewproj_matrix) #endif From be9d49c510ea56aaca83e8c80456a70810ce2bef Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Wed, 27 Feb 2013 16:15:59 +0100 Subject: [PATCH 803/916] Do not hide pinned windows during loadings --- apps/openmw/mwgui/windowmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1dc11f2c4..e17190b02 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -424,6 +424,12 @@ void WindowManager::updateVisible() MyGUI::PointerManager::getInstance().setVisible(false); break; case GM_Loading: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + MyGUI::PointerManager::getInstance().setVisible(false); break; case GM_Video: From 03ca7f6123e250222bc133f9017f5d8b0aa5e01b Mon Sep 17 00:00:00 2001 From: Sergey Shambir Date: Wed, 27 Feb 2013 23:45:09 +0400 Subject: [PATCH 804/916] NIF: added NiStencilProperty record handling NiStencilProperty appears in Better Clothes plugin. If it not handled, some parts of NPCs bodies will be not rendered. --- components/nif/nif_file.cpp | 1 + components/nif/nif_file.hpp | 1 + components/nif/property.hpp | 57 ++++++++++++++++++++++++++ components/nif/record.hpp | 1 + components/nifogre/ogre_nif_loader.cpp | 2 + 5 files changed, 62 insertions(+) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 58d1bc9b8..ba3a7513b 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -256,6 +256,7 @@ void NIFFile::parse() else if(rec == "NiDitherProperty") { r = new NiDitherProperty; r->recType = RC_NiDitherProperty; } else if(rec == "NiWireframeProperty") { r = new NiWireframeProperty; r->recType = RC_NiWireframeProperty; } else if(rec == "NiSpecularProperty") { r = new NiSpecularProperty; r->recType = RC_NiSpecularProperty; } + else if(rec == "NiStencilProperty") { r = new NiStencilProperty; r->recType = RC_NiStencilProperty; } // Controllers else if(rec == "NiVisController") { r = new NiVisController; r->recType = RC_NiVisController; } diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index e8884cd4d..5e9694f4b 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -158,6 +158,7 @@ public: short getShort() { return read_le16(); } unsigned short getUShort() { return read_le16(); } int getInt() { return read_le32(); } + unsigned int getUInt() { return read_le32(); } float getFloat() { return read_le32f(); } Ogre::Vector2 getVector2() { diff --git a/components/nif/property.hpp b/components/nif/property.hpp index b24e49b47..046fb0465 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -257,9 +257,66 @@ struct S_AlphaProperty } }; +/* + Docs taken from: + http://niftools.sourceforge.net/doc/nif/NiStencilProperty.html + */ +struct S_StencilProperty +{ + // Is stencil test enabled? + unsigned char enabled; + + /* + 0 TEST_NEVER + 1 TEST_LESS + 2 TEST_EQUAL + 3 TEST_LESS_EQUAL + 4 TEST_GREATER + 5 TEST_NOT_EQUAL + 6 TEST_GREATER_EQUAL + 7 TEST_ALWAYS + */ + int compareFunc; + unsigned stencilRef; + unsigned stencilMask; + /* + Stencil test fail action, depth test fail action and depth test pass action: + 0 ACTION_KEEP + 1 ACTION_ZERO + 2 ACTION_REPLACE + 3 ACTION_INCREMENT + 4 ACTION_DECREMENT + 5 ACTION_INVERT + */ + int failAction; + int zFailAction; + int zPassAction; + /* + Face draw mode: + 0 DRAW_CCW_OR_BOTH + 1 DRAW_CCW [default] + 2 DRAW_CW + 3 DRAW_BOTH + */ + int drawMode; + + void read(NIFFile *nif) + { + enabled = nif->getChar(); + compareFunc = nif->getInt(); + stencilRef = nif->getUInt(); + stencilMask = nif->getUInt(); + failAction = nif->getInt(); + zFailAction = nif->getInt(); + zPassAction = nif->getInt(); + drawMode = nif->getInt(); + } +}; + typedef StructPropT NiAlphaProperty; typedef StructPropT NiMaterialProperty; typedef StructPropT NiVertexColorProperty; +typedef StructPropT NiStencilProperty; } // Namespace #endif diff --git a/components/nif/record.hpp b/components/nif/record.hpp index d5f65e83a..073f4657c 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -48,6 +48,7 @@ enum RecordType RC_NiDitherProperty, RC_NiWireframeProperty, RC_NiSpecularProperty, + RC_NiStencilProperty, RC_NiVisController, RC_NiGeomMorpherController, RC_NiKeyframeController, diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5042f666a..052334f1d 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -586,6 +586,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String m = static_cast(pr); else if (pr->recType == Nif::RC_NiAlphaProperty) a = static_cast(pr); + else if (pr->recType == Nif::RC_NiStencilProperty) + /* unused */; else warn("Skipped property type: "+pr->recName); } From bfe80bb8dc0fa780ab065bb2086a4a7fc6663016 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 27 Feb 2013 12:33:36 -0800 Subject: [PATCH 805/916] Avoid duplicating skeletons due to casing issues Manually created resource names are apparently always case sensitive, causing some skeletons to get loaded multiple times. --- apps/openmw/mwrender/animation.cpp | 15 ++------ components/nifogre/ogre_nif_loader.cpp | 51 ++++++++++++++------------ components/nifogre/ogre_nif_loader.hpp | 2 +- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 394e25b50..cc926e685 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -53,8 +53,6 @@ void Animation::setAnimationSources(const std::vector &names) if(!mEntityList.mSkelBase) return; - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - mCurrentAnim = NULL; mCurrentKeys = NULL; mAnimVelocity = 0.0f; @@ -62,19 +60,14 @@ void Animation::setAnimationSources(const std::vector &names) mNonAccumRoot = NULL; mSkeletonSources.clear(); - std::vector::const_iterator nameiter = names.begin(); + std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { - Ogre::SkeletonPtr skel = skelMgr.getByName(*nameiter); + Ogre::SkeletonPtr skel = NifOgre::Loader::getSkeleton(*nameiter); if(skel.isNull()) { - NifOgre::Loader::createSkeleton(*nameiter); - skel = skelMgr.getByName(*nameiter); - if(skel.isNull()) - { - std::cerr<< "Failed to get skeleton source "<<*nameiter <touch(); diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 5042f666a..b3d70bb1f 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -452,7 +452,8 @@ void loadResource(Ogre::Resource *resource) } } -bool createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) + +static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) { /* We need to be a little aggressive here, since some NIFs have a crap-ton * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: @@ -463,7 +464,7 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif if(!node->boneTrafo) { if(node->recType == Nif::RC_NiTriShape) - return false; + return Ogre::SkeletonPtr(); if(node->controller.empty() && node->name != "AttachLight") { if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) @@ -474,18 +475,18 @@ bool createSkeleton(const std::string &name, const std::string &group, const Nif { if(!children[i].empty()) { - if(createSkeleton(name, group, children[i].getPtr())) - return true; + Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); + if(!skel.isNull()) + return skel; } } - return false; + return Ogre::SkeletonPtr(); } } } Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - skelMgr.create(name, group, true, &sLoaders[name]); - return true; + return skelMgr.create(name, group, true, &sLoaders[name]); } }; @@ -1140,10 +1141,7 @@ MeshInfoList Loader::load(const std::string &name, const std::string &group) bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); if(!hasSkel) - { - NIFSkeletonLoader skelldr; - hasSkel = skelldr.createSkeleton(name, group, node); - } + hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); NIFMeshLoader meshldr(name, group); if(hasSkel) @@ -1253,30 +1251,35 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } -bool Loader::createSkeleton(const std::string &name, const std::string &group) +Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group) { - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) + Ogre::SkeletonPtr skel; + + Misc::StringUtils::toLower(name); + skel = Ogre::SkeletonManager::getSingleton().getByName(name); + if(!skel.isNull()) + return skel; + + Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); + if(nif->numRecords() < 1) { - nif.warn("Found no NIF records in "+name+"."); - return false; + nif->warn("Found no NIF records in "+name+"."); + return skel; } // The first record is assumed to be the root node - Nif::Record const *r = nif.getRecord(0); + const Nif::Record *r = nif->getRecord(0); assert(r != NULL); - Nif::Node const *node = dynamic_cast(r); + const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return false; + nif->warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return skel; } - NIFSkeletonLoader skelldr; - return skelldr.createSkeleton(name, group, node); + return NIFSkeletonLoader::createSkeleton(name, group, node); } diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index 7a7b0c5a1..eae37dd8a 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -74,7 +74,7 @@ public: std::string name, const std::string &group="General"); - static bool createSkeleton(const std::string &name, const std::string &group="General"); + static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); }; } From 3ed0bf97a8a94d98e5d274f7a45a2f72e0b0bb63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 27 Feb 2013 13:16:27 -0800 Subject: [PATCH 806/916] Share the space with the parent entity only when there's real skinned meshes The existence of a base skeleton doesn't mean it shares the same bone structure. If there isn't an actual skinned entity besides the base, simply attach it to the bone like unskinned meshes should be. --- components/nifogre/ogre_nif_loader.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index b3d70bb1f..4d047ae8b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -1204,14 +1204,20 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(meshes.size() == 0) return entitylist; + bool isskinned = false; Ogre::SceneManager *sceneMgr = parentNode->getCreator(); std::string filter = "@shape=tri "+bonename; Misc::StringUtils::toLower(filter); for(size_t i = 0;i < meshes.size();i++) { Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); - if(!entitylist.mSkelBase && ent->hasSkeleton()) - entitylist.mSkelBase = ent; + if(!entitylist.mSkelBase) + { + if(ent->hasSkeleton()) + entitylist.mSkelBase = ent; + } + else if(!isskinned && ent->hasSkeleton()) + isskinned = true; entitylist.mEntities.push_back(ent); } @@ -1219,7 +1225,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(bonename.find("Left") != std::string::npos) scale.x *= -1.0f; - if(entitylist.mSkelBase) + if(isskinned) { for(size_t i = 0;i < entitylist.mEntities.size();i++) { From b93eb844010f3002bb1acb15534f82f2a5af55c0 Mon Sep 17 00:00:00 2001 From: lazydev Date: Thu, 28 Feb 2013 02:43:03 +0400 Subject: [PATCH 807/916] fix for https://bugs.openmw.org/issues/573 --- components/esm/esmreader.hpp | 16 ++++++++-------- components/esm/loadappa.cpp | 27 +++++++++++++++++++++------ components/esm/loadappa.hpp | 6 ++++-- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 45d6d9164..ae876edf8 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -37,14 +37,14 @@ public: *************************************************************************/ int getVer() const { return mCtx.header.version; } - float getFVer() { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } - int getSpecial() { return mSpf; } - int getType() { return mCtx.header.type; } - const std::string getAuthor() { return mCtx.header.author.toString(); } - const std::string getDesc() { return mCtx.header.desc.toString(); } + float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } + int getSpecial() const { return mSpf; } + int getType() const { return mCtx.header.type; } + const std::string getAuthor() const { return mCtx.header.author.toString(); } + const std::string getDesc() const { return mCtx.header.desc.toString(); } const SaveData &getSaveData() const { return mSaveData; } - const MasterList &getMasters() { return mMasters; } - const NAME &retSubName() { return mCtx.subName; } + const MasterList &getMasters() const { return mMasters; } + const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } /************************************************************************* @@ -85,7 +85,7 @@ public: int mIdx; void setIndex(const int index) {mIdx = index; mCtx.index = index;} const int getIndex() {return mIdx;} - + void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} std::vector *getGlobalReaderList() {return mGlobalReaderList;} diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index f5e7e10e1..80922e2cb 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -7,13 +7,28 @@ namespace ESM { void Apparatus::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); - esm.getHNT(mData, "AADT", 16); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNString("ITEX"); + // we will not treat duplicated subrecords as errors here + while (esm.hasMoreSubs()) + { + esm.getSubName(); + NAME subName = esm.retSubName(); + + if (subName == "MODL") + mModel = esm.getHString(); + else if (subName == "FNAM") + mName = esm.getHString(); + else if (subName == "AADT") + esm.getHT(mData); + else if (subName == "SCRI") + mScript = esm.getHString(); + else if (subName == "ITEX") + mIcon = esm.getHString(); + else + esm.fail("wrong subrecord type " + subName.toString() + " for APPA record"); + } } -void Apparatus::save(ESMWriter &esm) + +void Apparatus::save(ESMWriter &esm) const { esm.writeHNCString("MODL", mModel); esm.writeHNCString("FNAM", mName); diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 486a559f8..a1daeb123 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_ESM_APPA_H #define OPENMW_ESM_APPA_H +#include "esmcommon.hpp" #include namespace ESM @@ -13,8 +14,9 @@ class ESMWriter; * Alchemist apparatus */ -struct Apparatus +class Apparatus { +public: enum AppaType { MortarPestle = 0, @@ -35,7 +37,7 @@ struct Apparatus std::string mId, mModel, mIcon, mScript, mName; void load(ESMReader &esm); - void save(ESMWriter &esm); + void save(ESMWriter &esm) const; }; } #endif From d5aa975675c2bacfe91dd7199143b79fa4ac324d Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Wed, 27 Feb 2013 23:44:20 +0100 Subject: [PATCH 808/916] Fix some issues that seem to have appeared in the CMake configuration. --- CMakeLists.txt | 6 +++--- cmake/OpenMWMacros.cmake | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbab83690..4b092e922 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,7 +378,7 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_SOURCE_DIR}/GPL3.txt" "${OpenMW_SOURCE_DIR}/OFL.txt" - "${OpenMW_SOURCE_DIR}/Bitstream Vera License.txt" + "${OpenMW_SOURCE_DIR}/DejaVu Font License.txt" "${OpenMW_SOURCE_DIR}/Daedric Font License.txt" "${OpenMW_BINARY_DIR}/launcher.qss" "${OpenMW_BINARY_DIR}/settings-default.cfg" @@ -389,7 +389,7 @@ if(WIN32) INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") SET(CPACK_GENERATOR "NSIS") - SET(CPACK_PACKAGE_NAME "OpenMW ${OPENMW_VERSION}") + SET(CPACK_PACKAGE_NAME "OpenMW") SET(CPACK_PACKAGE_VENDOR "OpenMW.org") SET(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) SET(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR}) @@ -404,7 +404,7 @@ if(WIN32) SET(CPACK_RESOURCE_FILE_README "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/readme.txt") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") - SET(CPACK_NSIS_DISPLAY_NAME "OpenMW") + SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index f2382fd8a..f66dbf2c4 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -2,7 +2,7 @@ macro (add_openmw_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND OPENMW_FILES "${f}") @@ -14,7 +14,7 @@ endmacro (add_openmw_dir) macro (add_component_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND COMPONENT_FILES "${f}") @@ -26,12 +26,12 @@ endmacro (add_component_dir) macro (add_component_qt_dir dir) set (files) foreach (u ${ARGN}) -file (GLOB ALL ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.[ch]pp") +file (GLOB ALL "${dir}/${u}.[ch]pp") foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND COMPONENT_FILES "${f}") endforeach (f) -file (GLOB MOC_H ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/${u}.hpp") +file (GLOB MOC_H "${dir}/${u}.hpp") foreach (fi ${MOC_H}) list (APPEND COMPONENT_MOC_FILES "${fi}") endforeach (fi) From 0e8ff22d6fabe839380acdb2cde3fd11706ebbab Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Thu, 28 Feb 2013 07:20:01 +0400 Subject: [PATCH 809/916] Only install binaries which are enabled to be built --- CMakeLists.txt | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbab83690..e8d5f23c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -657,10 +657,18 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) # Install binaries INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) - INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + IF(BUILD_LAUNCHER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_LAUNCHER) + IF(BUILD_ESMTOOL) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_ESMTOOL) + IF(BUILD_MWINIIMPORTER) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_MWINIIMPORTER) + IF(BUILD_OPENCS) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_OPENCS) # Install icon and .desktop INSTALL(FILES "${OpenMW_SOURCE_DIR}/apps/launcher/resources/images/openmw.png" DESTINATION "${ICONDIR}") @@ -674,5 +682,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) # Install resources INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) - INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) + IF(BUILD_LAUNCHER) + INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) + ENDIF(BUILD_LAUNCHER) endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) From 3bd228f71b1dab4f5d454b1a1cb7b2506a94afaa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 11:50:29 +0100 Subject: [PATCH 810/916] fix for global variables of type short --- components/esm/loadglob.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 429c6ff1d..9e20578ce 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -20,6 +20,14 @@ void Global::load(ESMReader &esm) // Note: Both floats and longs are represented as floats. esm.getHNT(mValue, "FLTV"); + + if (mType==VT_Short) + { + if (mValue!=mValue) + mValue = 0; // nan + else + mValue = static_cast (mValue); + } } void Global::save(ESMWriter &esm) From f75681d89b3d29cf1561f0a261829f8b8ad6d347 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 12:12:51 +0100 Subject: [PATCH 811/916] Ignore ESX header version --- components/esm/esmreader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index eca0d7854..41a2f738a 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -77,8 +77,9 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) // Get the header getHNT(mCtx.header, "HEDR", 300); - if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) - fail("Unsupported file format version"); + // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. + //if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) + //fail("Unsupported file format version"); while (isNextSub("MAST")) { From 6683e43efcfefffc069fa172b2e0cdd15bb04891 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 12:35:18 +0100 Subject: [PATCH 812/916] Removed commented code --- components/esm/esmreader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 41a2f738a..b4f581d7e 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -78,8 +78,6 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) getHNT(mCtx.header, "HEDR", 300); // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. - //if (mCtx.header.version != VER_12 && mCtx.header.version != VER_13) - //fail("Unsupported file format version"); while (isNextSub("MAST")) { From ffd96c771593bc85205e53c487adebf4bdcaf41e Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 13:19:05 +0100 Subject: [PATCH 813/916] Removed "Unloading Cell..." text from loading screen OpenMW unloads the cell so fast, it's hardly noticable. This commit gets rid of the "flicker" every time a cell loads. --- apps/openmw/mwworld/scene.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index fb7653401..99c1793fe 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -75,7 +75,7 @@ namespace MWWorld { std::cout << "Unloading cell\n"; ListHandles functor; - + (*iter)->forEach(functor); { // silence annoying g++ warning @@ -217,7 +217,7 @@ namespace MWWorld } } - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); + //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; } @@ -360,7 +360,7 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); + //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; From d4aa33b9a7da71682e9afa0cea01b65f9ce57453 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 15:58:03 +0100 Subject: [PATCH 814/916] Removing the unloading cells part instead of just commenting them. --- apps/openmw/mwworld/scene.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 99c1793fe..c15baf43b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -75,7 +75,7 @@ namespace MWWorld { std::cout << "Unloading cell\n"; ListHandles functor; - + (*iter)->forEach(functor); { // silence annoying g++ warning @@ -217,7 +217,6 @@ namespace MWWorld } } - //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; } @@ -360,7 +359,6 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - //MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Unloading cells", 0, current, numUnload); unloadCell (active++); ++current; From a6fb58bc59598f77c2ccc415b47ce475b7cf073a Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 16:31:24 +0100 Subject: [PATCH 815/916] Using "Loading Exterior" and "Loading Interior" instead of "Loading Cell" This commit replaces the default "Loading Cell" text with "Loading Interior" and "Loading Exterior" --- apps/openmw/mwworld/scene.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c15baf43b..1e8f6d339 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -27,13 +27,10 @@ namespace { const MWWorld::Class& class_ = MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); - - size_t numRefs = cellRefList.mList.size(); int current = 0; for (typename T::List::iterator it = cellRefList.mList.begin(); it != cellRefList.mList.end(); it++) { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, current, numRefs); ++current; if (it->mData.getCount() || it->mData.isEnabled()) @@ -55,10 +52,6 @@ namespace } } } - else - { - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 1, 0, 1); - } } } @@ -216,7 +209,6 @@ namespace MWWorld continue; } } - unloadCell (active++); ++current; } @@ -265,7 +257,9 @@ namespace MWWorld { CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, current, numLoad); + //Loading Exterior loading text + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Exterior", 0, current, numLoad); + loadCell (cell); ++current; } @@ -359,7 +353,6 @@ namespace MWWorld active = mActiveCells.begin(); while (active!=mActiveCells.end()) { - unloadCell (active++); ++current; } @@ -367,7 +360,9 @@ namespace MWWorld // Load cell. std::cout << "cellName: " << cell->mCell->mName << std::endl; - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading cells", 0, 0, 1); + //Loading Interior loading text + MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Interior", 0, 0, 1); + loadCell (cell); mCurrentCell = cell; From f66f67eaa12f0fcddbb615648b478c2215c77d96 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 17:54:42 +0100 Subject: [PATCH 816/916] Loading text uses now the corresponding GMSTs --- apps/openmw/mwworld/scene.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 1e8f6d339..ecf783d6c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -169,12 +169,18 @@ namespace MWWorld void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) { Nif::NIFFile::CacheLock cachelock; + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); mRendering.preCellChange(mCurrentCell); // remove active MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + std::string loadingExteriorText; + + loadingExteriorText = gmst.find ("sLoadingMessage3")->getString(); + CellStoreCollection::iterator active = mActiveCells.begin(); // get the number of cells to unload @@ -258,7 +264,7 @@ namespace MWWorld CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); //Loading Exterior loading text - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Exterior", 0, current, numLoad); + MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingExteriorText, 0, current, numLoad); loadCell (cell); ++current; @@ -318,6 +324,13 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { + + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string loadingInteriorText; + loadingInteriorText = gmst.find ("sLoadingMessage2")->getString(); + CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); bool loadcell = (mCurrentCell == NULL); if(!loadcell) @@ -361,7 +374,7 @@ namespace MWWorld std::cout << "cellName: " << cell->mCell->mName << std::endl; //Loading Interior loading text - MWBase::Environment::get().getWindowManager ()->setLoadingProgress ("Loading Interior", 0, 0, 1); + MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingInteriorText, 0, 0, 1); loadCell (cell); From bd597f07ab85d667ced3c6ef4afce828db73705e Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:22:10 +0100 Subject: [PATCH 817/916] Centered the loading text --- files/mygui/openmw_loading_screen.layout | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 4b6861151..1e4bba5ed 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,7 +8,8 @@ - + + From c9a701cfa1cf0c4de63717357673c9044b1ae6f3 Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:25:18 +0100 Subject: [PATCH 818/916] Removed the 3 dots after the load text. --- apps/openmw/mwgui/loadingscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index dd5289edb..e7c7acb53 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -106,7 +106,7 @@ namespace MWGui float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading); assert(progress <= 1 && progress >= 0); - mLoadingText->setCaption(stage + "... "); + mLoadingText->setCaption(stage); mProgressBar->setProgressPosition (static_cast(progress * 1000)); static float loadingScreenFps = 30.f; From 06e077c07ca699fb50f1b3d965394291eb1ccdde Mon Sep 17 00:00:00 2001 From: vorenon Date: Thu, 28 Feb 2013 19:36:10 +0100 Subject: [PATCH 819/916] Removing all traces of "Open Morrowind". pvdk said it was ok to remove the header entirely --- components/files/fixedpath.hpp | 22 ---------------------- components/files/linuxpath.cpp | 22 ---------------------- components/files/linuxpath.hpp | 22 ---------------------- components/files/macospath.cpp | 22 ---------------------- components/files/macospath.hpp | 22 ---------------------- components/files/ogreplugin.hpp | 22 ---------------------- components/files/windowspath.hpp | 22 ---------------------- 7 files changed, 154 deletions(-) diff --git a/components/files/fixedpath.hpp b/components/files/fixedpath.hpp index dce4f96c2..a309dc9fb 100644 --- a/components/files/fixedpath.hpp +++ b/components/files/fixedpath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/fixedpath.hpp */ - #ifndef COMPONENTS_FILES_FIXEDPATH_HPP #define COMPONENTS_FILES_FIXEDPATH_HPP diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index 0f08b67fe..c974a91d3 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/linuxpath.cpp */ - #include "linuxpath.hpp" #if defined(__linux__) || defined(__FreeBSD__) diff --git a/components/files/linuxpath.hpp b/components/files/linuxpath.hpp index 09acd2be7..6acf2a2d5 100644 --- a/components/files/linuxpath.hpp +++ b/components/files/linuxpath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/linuxpath.hpp */ - #ifndef COMPONENTS_FILES_LINUXPATH_H #define COMPONENTS_FILES_LINUXPATH_H diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 9625612ad..9edcd6ef2 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/macospath.cpp */ - #include "macospath.hpp" #if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__) diff --git a/components/files/macospath.hpp b/components/files/macospath.hpp index 591c978aa..576ec1681 100644 --- a/components/files/macospath.hpp +++ b/components/files/macospath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/macospath.hpp */ - #ifndef COMPONENTS_FILES_MACOSPATH_H #define COMPONENTS_FILES_MACOSPATH_H diff --git a/components/files/ogreplugin.hpp b/components/files/ogreplugin.hpp index 2d56bfb47..6fcf61376 100644 --- a/components/files/ogreplugin.hpp +++ b/components/files/ogreplugin.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/ogreplugin.hpp */ - #ifndef COMPONENTS_FILES_OGREPLUGIN_H #define COMPONENTS_FILES_OGREPLUGIN_H diff --git a/components/files/windowspath.hpp b/components/files/windowspath.hpp index 7fe8bc955..6044b67c2 100644 --- a/components/files/windowspath.hpp +++ b/components/files/windowspath.hpp @@ -1,25 +1,3 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/windowspath.hpp */ - #ifndef COMPONENTS_FILES_WINDOWSPATH_HPP #define COMPONENTS_FILES_WINDOWSPATH_HPP From 3df34fb5ccbb8ec0f1870b7f9072ff6576a22dd9 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Thu, 28 Feb 2013 19:52:32 +0100 Subject: [PATCH 820/916] fix bug 574 --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4a79f77b8..2b943c50f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -274,13 +274,11 @@ namespace MWInput if (actionIsActive(A_MoveLeft)) { triedToMove = true; - mPlayer.setAutoMove (false); mPlayer.setLeftRight (-1); } else if (actionIsActive(A_MoveRight)) { triedToMove = true; - mPlayer.setAutoMove (false); mPlayer.setLeftRight (1); } else From f77ace088537a7a999decf39485affe7cb8d0080 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20S=C3=B6derberg?= Date: Thu, 28 Feb 2013 20:16:46 +0100 Subject: [PATCH 821/916] Removed the "hack" mygui.png and misc fixes for this. --- files/mygui/CMakeLists.txt | 1 - files/mygui/mwgui.png | Bin 13534 -> 0 bytes .../openmw_chargen_class_description.layout | 3 + files/mygui/openmw_chargen_race.layout | 45 +- files/mygui/openmw_dialogue_window.layout | 6 +- files/mygui/openmw_edit.skin.xml | 57 ++- files/mygui/openmw_edit_effect.layout | 8 +- files/mygui/openmw_hud_box.skin.xml | 75 +--- files/mygui/openmw_list.skin.xml | 415 +++++++----------- files/mygui/openmw_loading_screen.layout | 3 +- files/mygui/openmw_map_window_skin.xml | 2 +- files/mygui/openmw_scroll_skin.xml | 6 +- files/mygui/openmw_settings_window.layout | 26 +- 13 files changed, 250 insertions(+), 397 deletions(-) delete mode 100644 files/mygui/mwgui.png diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index e7e5b695e..beace5b81 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -9,7 +9,6 @@ set(MYGUI_FILES core.skin core.xml EBGaramond-Regular.ttf - mwgui.png Obliviontt.zip openmw_alchemy_window.layout openmw_book.layout diff --git a/files/mygui/mwgui.png b/files/mygui/mwgui.png deleted file mode 100644 index 318f16e41873af708fd31d302bf0726efbdf916c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13534 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 Zfjvhb*ux%p4FUc|9E<#-`SbJN{0~$*&Ncu5 diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 11031eb4e..8823e1e76 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,6 +4,9 @@ + + + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index a9ec9905d..4ef8da0f3 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -8,33 +8,52 @@ - + - + - - + + + + + + + + + - - - + + + + + + + + + - - - + + + + + + + + + - + @@ -42,11 +61,11 @@ - + - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index 1271a287b..9a9da72d4 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -3,13 +3,15 @@ + + - + - + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index 02fee4b17..da21385e2 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -1,55 +1,52 @@ + + + + + + - - - - + - - - - - - - - - - - - + + + + + + + + + + + + + - + + + + - - - - - - - - - - - - - + + + diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index 45ecb63ed..cad22c064 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -31,7 +31,7 @@ - + @@ -39,7 +39,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 464b6343a..23480e8d3 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -1,80 +1,31 @@ + - - - - - - - - + - - - - - - - + + + - - - - - - - - - - - - - - - - + + - - - - - - - - - + - - - - - - - + - - - - - - - - - - - - - - - + + + + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 64435451a..6631424cc 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -1,228 +1,107 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + + + @@ -234,81 +113,85 @@ - - - - + + + + - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - + - + - - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 1e4bba5ed..4b6861151 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,8 +8,7 @@ - - + diff --git a/files/mygui/openmw_map_window_skin.xml b/files/mygui/openmw_map_window_skin.xml index 0c6050969..13f18c6d3 100644 --- a/files/mygui/openmw_map_window_skin.xml +++ b/files/mygui/openmw_map_window_skin.xml @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index 70fad3f4b..1b94f0c29 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -2,12 +2,12 @@ - + - + - + diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2f9b5a67f..8d435bfd5 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -15,7 +15,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -64,35 +64,35 @@ - + - + - + - + - + @@ -117,7 +117,7 @@ - + @@ -133,7 +133,7 @@ - + @@ -192,7 +192,7 @@ - + @@ -208,7 +208,7 @@ - + @@ -233,7 +233,7 @@ - + @@ -241,7 +241,7 @@ - + From 3efbb5e728b5708ee738279ccbe15ed765efadf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 20:27:35 +0100 Subject: [PATCH 822/916] Don't try to render a map in empty cells --- apps/openmw/mwrender/localmap.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 601ee58e3..1a14b86bf 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -119,6 +119,10 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell) void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, AxisAlignedBox bounds) { + // if we're in an empty cell, don't bother rendering anything + if (bounds.isNull ()) + return; + mInterior = true; mBounds = bounds; From 0b629791a82cc2abcaa7b1c2b106a81763c56a57 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 20:40:32 +0100 Subject: [PATCH 823/916] reverting loading bar layout --- files/mygui/openmw_loading_screen.layout | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 4b6861151..1e4bba5ed 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -8,7 +8,8 @@ - + + From b7ab12e7cf4e919cdd664254163bf8c204be2771 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 21:12:13 +0100 Subject: [PATCH 824/916] Workaround to prevent the map drawing on top of the world button --- apps/openmw/mwgui/map_window.cpp | 19 +++++++++++++++++++ apps/openmw/mwgui/map_window.hpp | 3 +++ 2 files changed, 22 insertions(+) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 6f7f0eaab..52b108f85 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -13,6 +15,8 @@ #include "../mwrender/globalmap.hpp" +#include "widgets.hpp" + using namespace MWGui; LocalMapBase::LocalMapBase() @@ -96,6 +100,7 @@ void LocalMapBase::applyFogOfWar() : ""); } } + notifyMapChanged (); } void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) @@ -425,3 +430,17 @@ void MapWindow::notifyPlayerUpdate () { globalMapUpdatePlayer (); } + +void MapWindow::notifyMapChanged () +{ + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); +} diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index 4e2dd6756..39770a7a2 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -50,6 +50,7 @@ namespace MWGui void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); virtual void notifyPlayerUpdate() {} + virtual void notifyMapChanged() {} OEngine::GUI::Layout* mLayout; @@ -99,6 +100,8 @@ namespace MWGui virtual void onPinToggled(); virtual void notifyPlayerUpdate(); + virtual void notifyMapChanged(); + }; } #endif From 1168f153611cb7e017c092496f3b31c978cd090e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 12:17:58 -0800 Subject: [PATCH 825/916] Don't disable depth writes when blending is enabled --- apps/openmw/mwrender/activatoranimation.cpp | 3 +-- apps/openmw/mwrender/creatureanimation.cpp | 3 +-- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/objects.cpp | 3 +-- components/nifogre/ogre_nif_loader.cpp | 2 -- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 7bc89b917..a3332d4b5 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -42,8 +42,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) while (passIt.hasMoreElements() && !transparent) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index b85c4dbbd..3adb0c448 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -43,8 +43,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) while (passIt.hasMoreElements() && !transparent) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 809e3f6d2..ce15841fc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -118,7 +118,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index add781459..9aa65ac99 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -148,8 +148,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) + if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) transparent = true; } } diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e6779ac1a..4d4a0d9c5 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -716,8 +716,6 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String blend_mode += getBlendFactor((alphaFlags>>1)&0xf); blend_mode += " "; blend_mode += getBlendFactor((alphaFlags>>5)&0xf); - - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); } else From 60f22194507c45f235c13928f3d7ca64e1629536 Mon Sep 17 00:00:00 2001 From: lazydev Date: Fri, 1 Mar 2013 00:46:05 +0400 Subject: [PATCH 826/916] fixed zini's norices --- components/esm/loadappa.cpp | 2 +- components/esm/loadappa.hpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 80922e2cb..643fefda5 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -28,7 +28,7 @@ void Apparatus::load(ESMReader &esm) } } -void Apparatus::save(ESMWriter &esm) const +void Apparatus::save(ESMWriter &esm) { esm.writeHNCString("MODL", mModel); esm.writeHNCString("FNAM", mName); diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index a1daeb123..820c44c59 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -1,7 +1,6 @@ #ifndef OPENMW_ESM_APPA_H #define OPENMW_ESM_APPA_H -#include "esmcommon.hpp" #include namespace ESM @@ -14,7 +13,7 @@ class ESMWriter; * Alchemist apparatus */ -class Apparatus +struct Apparatus { public: enum AppaType @@ -37,7 +36,7 @@ public: std::string mId, mModel, mIcon, mScript, mName; void load(ESMReader &esm); - void save(ESMWriter &esm) const; + void save(ESMWriter &esm); }; } #endif From 230136438b096d017ac490cc65347d73bc2b8854 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 22:17:07 +0100 Subject: [PATCH 827/916] minor cleanup --- components/esm/loadappa.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/components/esm/loadappa.hpp b/components/esm/loadappa.hpp index 820c44c59..486a559f8 100644 --- a/components/esm/loadappa.hpp +++ b/components/esm/loadappa.hpp @@ -15,7 +15,6 @@ class ESMWriter; struct Apparatus { -public: enum AppaType { MortarPestle = 0, From 2786cc67f61e9e4aa6338222491ec96c501c4f5d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 13:38:48 -0800 Subject: [PATCH 828/916] Fix loading empty NiTriShapeData records --- components/nif/data.hpp | 16 +++++++--------- components/nif/nif_file.cpp | 5 ++--- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 63df23b27..46b58da8f 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -142,20 +142,18 @@ public: { ShapeData::read(nif); - int tris = nif->getUShort(); - if(tris) - { - // We have three times as many vertices as triangles, so this - // is always equal to tris*3. - int cnt = nif->getInt(); - nif->getShorts(triangles, cnt); - } + /*int tris =*/ nif->getUShort(); + + // We have three times as many vertices as triangles, so this + // is always equal to tris*3. + int cnt = nif->getInt(); + nif->getShorts(triangles, cnt); // Read the match list, which lists the vertices that are equal to // vertices. We don't actually need need this for anything, so // just skip it. int verts = nif->getUShort(); - for(int i=0;igetUShort(); diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index ba3a7513b..6e806e7ec 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -220,11 +220,10 @@ void NIFFile::parse() for(size_t i = 0;i < recNum;i++) { - std::string rec = getString(); - //cout << i << ": " << rec.toString() << endl; - Record *r = NULL; + std::string rec = getString(); + /* These are all the record types we know how to read. This can be heavily optimized later if needed. For example, a From eaa6813917498b84eb3ea02adb3d2ab3b26e08ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 13:54:53 -0800 Subject: [PATCH 829/916] Workaround for meshes without any vertices --- components/nifogre/ogre_nif_loader.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index e6779ac1a..a86487854 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -844,9 +844,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Set the bounding box first BoundsFinder bounds; bounds.add(&srcVerts[0][0], srcVerts.size()); - // No idea why this offset is needed. It works fine without it if the - // vertices weren't transformed first, but otherwise it fails later on - // when the object is being inserted into the scene. + if(!bounds.isValid()) + { + float v[3] = { 0.0f, 0.0f, 0.0f }; + bounds.add(&v[0], 1); + } + mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); mesh->_setBoundingSphereRadius(bounds.getRadius()); From 1d988676febb8b0e6629f6ca9b2eff0bdec6512e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 28 Feb 2013 22:56:29 +0100 Subject: [PATCH 830/916] Local map: the obtained bounding box wasn't exactly accurate, getWorldBoundingBox seems to solve this. --- apps/openmw/mwrender/localmap.cpp | 5 ++++- apps/openmw/mwrender/objects.cpp | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 1a14b86bf..918ec4580 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -134,7 +134,7 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mAngle = angle.valueRadians(); mCellCamera->setOrientation(Quaternion::IDENTITY); - mCameraRotNode->setOrientation(Quaternion(Math::Cos(angle/2.f), 0, 0, -Math::Sin(angle/2.f))); + mCameraRotNode->setOrientation(Quaternion(Math::Cos(mAngle/2.f), 0, 0, -Math::Sin(mAngle/2.f))); // rotate the cell and merge the rotated corners to the bounding box Vector2 _center(bounds.getCenter().x, bounds.getCenter().y); @@ -156,6 +156,9 @@ void LocalMap::requestMap(MWWorld::Ptr::CellStore* cell, mBounds.merge(Vector3(c3.x, c3.y, 0)); mBounds.merge(Vector3(c4.x, c4.y, 0)); + // apply a little padding + mBounds.scale ((mBounds.getSize ()+Ogre::Vector3(1000,1000,0)) / mBounds.getSize ()); + Vector2 center(mBounds.getCenter().x, mBounds.getCenter().y); Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index add781459..e8ee3f95f 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -113,12 +113,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; NifOgre::EntityList entities = NifOgre::Loader::createEntities(insert, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) - { - const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); - bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(), - insert->_getDerivedPosition() + tmp.getMaximum()) - ); - } + bounds.merge(entities.mEntities[i]->getWorldBoundingBox(true)); + Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); float size = std::max(std::max(extents.x, extents.y), extents.z); From 2c05a7477cfc37faab23217c87fe7527aa2a9dbf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Feb 2013 17:16:28 -0800 Subject: [PATCH 831/916] Improve checks for texture resource names that include the "textures\" prefix --- components/nifogre/ogre_nif_loader.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index a86487854..85fbfea26 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -605,7 +605,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String */ static const char path[] = "textures\\"; - texName = path + st->filename; + texName = st->filename; + Misc::StringUtils::toLower(texName); + + if(texName.compare(0, sizeof(path)-1, path) != 0) + texName = path + texName; + Ogre::String::size_type pos = texName.rfind('.'); if(pos != Ogre::String::npos && texName.compare(pos, texName.length() - pos, ".dds") != 0) { @@ -616,18 +621,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) // verify, and revert if false (this call succeeds quickly, but fails slowly) if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = path + st->filename; - } - else if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - { - // workaround for Better Heads addon - size_t lastSlash = st->filename.rfind('\\'); - if (lastSlash != std::string::npos && lastSlash + 1 != st->filename.size()) { - texName = path + st->filename.substr(lastSlash + 1); - // workaround for Better Bodies addon - if (!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = st->filename; - } + texName = path + Misc::StringUtils::lowerCase(texName); } } else warn("Found internal texture, ignoring."); From d8f2d0195af6b9ac35560057412e0afb1544ec58 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 18:45:52 +0100 Subject: [PATCH 832/916] Got rid of the texture rotation hack by rendering the cursor manually. --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/engine.cpp | 4 - apps/openmw/mwgui/cursor.cpp | 130 +++++++++++++++++++++++++ apps/openmw/mwgui/cursor.hpp | 62 ++++++++++++ apps/openmw/mwgui/cursorreplace.cpp | 16 --- apps/openmw/mwgui/cursorreplace.hpp | 16 --- apps/openmw/mwgui/windowmanagerimp.cpp | 19 +++- apps/openmw/mwgui/windowmanagerimp.hpp | 2 + files/mygui/openmw_pointer.xml | 11 ++- files/mygui/openmw_resources.xml | 21 ---- libs/openengine/gui/manager.cpp | 2 +- 11 files changed, 219 insertions(+), 68 deletions(-) create mode 100644 apps/openmw/mwgui/cursor.cpp create mode 100644 apps/openmw/mwgui/cursor.hpp delete mode 100644 apps/openmw/mwgui/cursorreplace.cpp delete mode 100644 apps/openmw/mwgui/cursorreplace.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index b3f4cd57b..7cfeb84c5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -26,11 +26,11 @@ add_openmw_dir (mwinput add_openmw_dir (mwgui text_input widgets race class birth review windowmanagerimp console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list + map_window window_pinnable_base tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog trainingwindow travelwindow imagebutton exposedwindow + enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 6f59349fd..d14696cdd 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -18,7 +18,6 @@ #include "mwinput/inputmanagerimp.hpp" #include "mwgui/windowmanagerimp.hpp" -#include "mwgui/cursorreplace.hpp" #include "mwscript/scriptmanagerimp.hpp" #include "mwscript/extensions.hpp" @@ -333,9 +332,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) loadBSA(); - // cursor replacer (converts the cursor from the bsa so they can be used by mygui) - MWGui::CursorReplace replacer; - // Create the world mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp new file mode 100644 index 000000000..852eea29a --- /dev/null +++ b/apps/openmw/mwgui/cursor.cpp @@ -0,0 +1,130 @@ +#include "cursor.hpp" + +#include +#include +#include +#include +#include + +#include + + +namespace MWGui +{ + + + ResourceImageSetPointerFix::ResourceImageSetPointerFix() : + mImageSet(nullptr) + { + } + + ResourceImageSetPointerFix::~ResourceImageSetPointerFix() + { + } + + void ResourceImageSetPointerFix::deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version) + { + Base::deserialization(_node, _version); + + MyGUI::xml::ElementEnumerator info = _node->getElementEnumerator(); + while (info.next("Property")) + { + const std::string& key = info->findAttribute("key"); + const std::string& value = info->findAttribute("value"); + + if (key == "Point") + mPoint = MyGUI::IntPoint::parse(value); + else if (key == "Size") + mSize = MyGUI::IntSize::parse(value); + else if (key == "Rotation") + mRotation = MyGUI::utility::parseInt(value); + else if (key == "Resource") + mImageSet = MyGUI::ResourceManager::getInstance().getByName(value)->castType(); + } + } + + int ResourceImageSetPointerFix::getRotation() + { + return mRotation; + } + + void ResourceImageSetPointerFix::setImage(MyGUI::ImageBox* _image) + { + if (mImageSet != nullptr) + _image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0)); + } + + void ResourceImageSetPointerFix::setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point) + { + _image->setCoord(_point.left - mPoint.left, _point.top - mPoint.top, mSize.width, mSize.height); + } + + MyGUI::ResourceImageSetPtr ResourceImageSetPointerFix:: getImageSet() + { + return mImageSet; + } + + MyGUI::IntPoint ResourceImageSetPointerFix::getHotSpot() + { + return mPoint; + } + + MyGUI::IntSize ResourceImageSetPointerFix::getSize() + { + return mSize; + } + + // ---------------------------------------------------------------------------------------- + + Cursor::Cursor() + { + // hide mygui's pointer since we're rendering it ourselves (because mygui's pointer doesn't support rotation) + MyGUI::PointerManager::getInstance().setVisible(false); + + MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &Cursor::onCursorChange); + + mWidget = MyGUI::Gui::getInstance().createWidget("RotatingSkin",0,0,0,0,MyGUI::Align::Default,"Pointer",""); + + onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); + } + + Cursor::~Cursor() + { + } + + void Cursor::onCursorChange(const std::string &name) + { + ResourceImageSetPointerFix* imgSetPtr = dynamic_cast( + MyGUI::PointerManager::getInstance().getByName(name)); + assert(imgSetPtr != NULL); + + MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet(); + + std::string texture = imgSet->getIndexInfo(0,0).texture; + + mSize = imgSetPtr->getSize(); + mHotSpot = imgSetPtr->getHotSpot(); + + int rotation = imgSetPtr->getRotation(); + + mWidget->setImageTexture(texture); + MyGUI::ISubWidget* main = mWidget->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + rotatingSubskin->setAngle(Ogre::Degree(rotation).valueRadians()); + } + + void Cursor::update() + { + MyGUI::IntPoint position = MyGUI::InputManager::getInstance().getMousePosition(); + + mWidget->setPosition(position - mHotSpot); + mWidget->setSize(mSize); + } + + void Cursor::setVisible(bool visible) + { + mWidget->setVisible(visible); + } + +} diff --git a/apps/openmw/mwgui/cursor.hpp b/apps/openmw/mwgui/cursor.hpp new file mode 100644 index 000000000..3a4a05f4c --- /dev/null +++ b/apps/openmw/mwgui/cursor.hpp @@ -0,0 +1,62 @@ +#ifndef MWGUI_CURSOR_H +#define MWGUI_CURSOR_H + +#include +#include +#include + +namespace MWGui +{ + + /// \brief Allows us to get the members of + /// ResourceImageSetPointer that we need. + /// \example MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + /// MyGUI::ResourceManager::getInstance().load("core.xml"); + class ResourceImageSetPointerFix : + public MyGUI::IPointer + { + MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix ) + + public: + ResourceImageSetPointerFix(); + virtual ~ResourceImageSetPointerFix(); + + virtual void deserialization(MyGUI::xml::ElementPtr _node, MyGUI::Version _version); + + virtual void setImage(MyGUI::ImageBox* _image); + virtual void setPosition(MyGUI::ImageBox* _image, const MyGUI::IntPoint& _point); + + //and now for the whole point of this class, allow us to get + //the hot spot, the image and the size of the cursor. + virtual MyGUI::ResourceImageSetPtr getImageSet(); + virtual MyGUI::IntPoint getHotSpot(); + virtual MyGUI::IntSize getSize(); + virtual int getRotation(); + + private: + MyGUI::IntPoint mPoint; + MyGUI::IntSize mSize; + MyGUI::ResourceImageSetPtr mImageSet; + int mRotation; // rotation in degrees + }; + + class Cursor + { + public: + Cursor(); + ~Cursor(); + void update (); + + void setVisible (bool visible); + + void onCursorChange (const std::string& name); + + private: + MyGUI::ImageBox* mWidget; + + MyGUI::IntSize mSize; + MyGUI::IntPoint mHotSpot; + }; +} + +#endif diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp deleted file mode 100644 index 2079538fc..000000000 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "cursorreplace.hpp" - -#include -#include - -#include -#include - -using namespace MWGui; - -CursorReplace::CursorReplace() -{ - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize1.png", -45); - OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45); -} diff --git a/apps/openmw/mwgui/cursorreplace.hpp b/apps/openmw/mwgui/cursorreplace.hpp deleted file mode 100644 index 06fe28e39..000000000 --- a/apps/openmw/mwgui/cursorreplace.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef GAME_CURSORREPLACE_H -#define GAME_CURSORREPLACE_H - -#include - -namespace MWGui -{ - /// \brief MyGUI does not support rotating cursors, so we have to do it manually - class CursorReplace - { - public: - CursorReplace(); - }; -} - -#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e17190b02..1138f62fa 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -53,6 +53,7 @@ #include "trainingwindow.hpp" #include "imagebutton.hpp" #include "exposedwindow.hpp" +#include "cursor.hpp" using namespace MWGui; @@ -130,6 +131,9 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + MyGUI::ResourceManager::getInstance().load("core.xml"); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Get size info from the Gui object @@ -178,6 +182,8 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + mCursor = new Cursor(); + // The HUD is always on mHud->setVisible(true); @@ -236,6 +242,7 @@ WindowManager::~WindowManager() delete mTrainingWindow; delete mCountDialog; delete mQuickKeysMenu; + delete mCursor; cleanupGarbage(); @@ -262,6 +269,8 @@ void WindowManager::update() mHud->setFPS(mFPS); mHud->setTriangleCount(mTriangleCount); mHud->setBatchCount(mBatchCount); + + mCursor->update(); } void WindowManager::updateVisible() @@ -293,7 +302,7 @@ void WindowManager::updateVisible() mHud->setVisible(true); // Mouse is visible whenever we're not in game mode - MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); + mCursor->setVisible(isGuiMode()); bool gameMode = !isGuiMode(); @@ -421,7 +430,7 @@ void WindowManager::updateVisible() break; case GM_LoadingWallpaper: mHud->setVisible(false); - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); break; case GM_Loading: // Show the pinned windows @@ -430,10 +439,10 @@ void WindowManager::updateVisible() mInventoryWindow->setVisible(mInventoryWindow->pinned()); mSpellWindow->setVisible(mSpellWindow->pinned()); - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); break; case GM_Video: - MyGUI::PointerManager::getInstance().setVisible(false); + mCursor->setVisible(false); mHud->setVisible(false); break; default: @@ -755,7 +764,7 @@ void WindowManager::setSpellVisibility(bool visible) void WindowManager::setMouseVisible(bool visible) { - MyGUI::PointerManager::getInstance().setVisible(visible); + mCursor->setVisible(visible); } void WindowManager::setDragDrop(bool dragDrop) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index f57421137..e2d64a855 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -72,6 +72,7 @@ namespace MWGui class SpellCreationDialog; class EnchantingDialog; class TrainingWindow; + class Cursor; class WindowManager : public MWBase::WindowManager { @@ -260,6 +261,7 @@ namespace MWGui EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; Translation::Storage& mTranslationDataStorage; + Cursor* mCursor; CharacterCreation* mCharGen; diff --git a/files/mygui/openmw_pointer.xml b/files/mygui/openmw_pointer.xml index 42ee5d435..cf21037f8 100644 --- a/files/mygui/openmw_pointer.xml +++ b/files/mygui/openmw_pointer.xml @@ -5,26 +5,31 @@ + + - + + - + + - + + diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index 5a695515d..e47ff6386 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -17,27 +17,6 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 925891e1b..e5a164b81 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -53,7 +53,7 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Create GUI mGui = new Gui(); - mGui->initialise("core.xml"); + mGui->initialise(""); } void MyGUIManager::shutdown() From 166d529c5071bd88e59374cfa7ba9078e47eee86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 13:26:31 -0800 Subject: [PATCH 833/916] Ensure the material is properly built after creating it --- components/nifogre/ogre_nif_loader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 4d4a0d9c5..c856c4ab3 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -733,6 +733,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(((alphaFlags>>13)&1) ? "off" : "on"))); + sh::Factory::getInstance()._ensureMaterial(matname, "Default"); return matname; } From 238a8feb1819d1b1b430a0fd5211b13b71998e79 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 13:27:25 -0800 Subject: [PATCH 834/916] Fix transparency checks --- apps/openmw/mwrender/activatoranimation.cpp | 9 +++---- apps/openmw/mwrender/creatureanimation.cpp | 9 +++---- apps/openmw/mwrender/npcanimation.cpp | 29 ++++++++++++++++----- apps/openmw/mwrender/objects.cpp | 11 ++++---- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index a3332d4b5..0dc16ecb6 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -31,19 +31,18 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) Ogre::Entity *ent = mEntityList.mEntities[i]; bool transparent = false; - for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) { Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements() && !transparent) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements() && !transparent) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 3adb0c448..73bb80547 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -32,19 +32,18 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) ent->setVisibilityFlags(RV_Actors); bool transparent = false; - for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) { Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements() && !transparent) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements() && !transparent) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index ce15841fc..1f1cd0530 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -107,19 +107,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor base->setVisibilityFlags(mVisibilityFlags); bool transparent = false; - for(unsigned int j=0;j < base->getNumSubEntities();++j) + for(unsigned int j=0;!transparent && j < base->getNumSubEntities();++j) { Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } @@ -322,8 +321,26 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int std::vector &parts = entities.mEntities; for(size_t i = 0;i < parts.size();i++) { - parts[i]->setVisibilityFlags(mVisibilityFlags); parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + parts[i]->setVisibilityFlags(mVisibilityFlags); + + bool transparent = false; + for(unsigned int j=0;!transparent && j < parts[i]->getNumSubEntities();++j) + { + Ogre::MaterialPtr mat = parts[i]->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while(!transparent && techIt.hasMoreElements()) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while(!transparent && passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); + transparent = pass->isTransparent(); + } + } + } + parts[i]->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } if(entities.mSkelBase) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 9aa65ac99..fb2b0e50a 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -134,22 +134,21 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool mBounds[ptr.getCell()].merge(bounds); bool transparent = false; - for(size_t i = 0;i < entities.mEntities.size();i++) + for(size_t i = 0;!transparent && i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; - for (unsigned int i=0; igetNumSubEntities(); ++i) + for(unsigned int i=0;!transparent && i < ent->getNumSubEntities(); ++i) { Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + while(!transparent && techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + while(!transparent && passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); - if(pass->getSourceBlendFactor() != Ogre::SBF_ONE || pass->getDestBlendFactor() != Ogre::SBF_ZERO) - transparent = true; + transparent = pass->isTransparent(); } } } From 9810eafe230104ba4356bc5f53d6ee74bdaa3079 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 22:27:53 +0100 Subject: [PATCH 835/916] Removing now unused oengine/imagerotate --- CMakeLists.txt | 1 - libs/openengine/ogre/imagerotate.cpp | 88 ---------------------------- libs/openengine/ogre/imagerotate.hpp | 27 --------- 3 files changed, 116 deletions(-) delete mode 100644 libs/openengine/ogre/imagerotate.cpp delete mode 100644 libs/openengine/ogre/imagerotate.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b976df57..e583f23d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,7 +74,6 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/fader.cpp - ${LIBDIR}/openengine/ogre/imagerotate.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp deleted file mode 100644 index 3dd584078..000000000 --- a/libs/openengine/ogre/imagerotate.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "imagerotate.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Ogre; -using namespace OEngine::Render; - -void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) -{ - Root* root = Ogre::Root::getSingletonPtr(); - - std::string destImageRot = std::string(destImage) + std::string("_rot"); - - SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); - Camera* camera = sceneMgr->createCamera("ImageRotateCamera"); - - MaterialPtr material = MaterialManager::getSingleton().create("ImageRotateMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - material->getTechnique(0)->getPass(0)->setLightingEnabled(false); - material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(sourceImage); - Degree deg(angle); - tus->setTextureRotate(Radian(deg.valueRadians())); - tus->setTextureAddressingMode(TextureUnitState::TAM_BORDER); - tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); - - Rectangle2D* rect = new Rectangle2D(true); - rect->setCorners(-1.0, 1.0, 1.0, -1.0); - rect->setMaterial("ImageRotateMaterial"); - // Render the background before everything else - rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); - - // Use infinite AAB to always stay visible - AxisAlignedBox aabInf; - aabInf.setInfinite(); - rect->setBoundingBox(aabInf); - - // Attach background to the scene - SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(rect); - - // retrieve image width and height - TexturePtr sourceTexture = TextureManager::getSingleton().getByName(sourceImage); - unsigned int width = sourceTexture->getWidth(); - unsigned int height = sourceTexture->getHeight(); - - TexturePtr destTextureRot = TextureManager::getSingleton().createManual( - destImageRot, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_FLOAT16_RGBA, - TU_RENDERTARGET); - - RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget(); - rtt->setAutoUpdated(false); - Viewport* vp = rtt->addViewport(camera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setBackgroundColour(ColourValue(0,0,0,0)); - - rtt->update(); - - //copy the rotated image to a static texture - TexturePtr destTexture = TextureManager::getSingleton().createManual( - destImage, - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - TEX_TYPE_2D, - width, height, - 0, - PF_FLOAT16_RGBA, - Ogre::TU_STATIC); - - destTexture->getBuffer()->blit(destTextureRot->getBuffer()); - - // remove all the junk we've created - TextureManager::getSingleton().remove(destImageRot); - MaterialManager::getSingleton().remove("ImageRotateMaterial"); - root->destroySceneManager(sceneMgr); - delete rect; -} diff --git a/libs/openengine/ogre/imagerotate.hpp b/libs/openengine/ogre/imagerotate.hpp deleted file mode 100644 index a3f6d662f..000000000 --- a/libs/openengine/ogre/imagerotate.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef OENGINE_OGRE_IMAGEROTATE_HPP -#define OENGINE_OGRE_IMAGEROTATE_HPP - -#include - -namespace OEngine -{ -namespace Render -{ - - /// Rotate an image by certain degrees and save as file, uses the GPU - /// Make sure Ogre Root is initialised before calling - class ImageRotate - { - public: - /** - * @param source image (file name - has to exist in an resource group) - * @param name of the destination texture to save to (in memory) - * @param angle in degrees to turn - */ - static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle); - }; - -} -} - -#endif From ef1678e47eaf1974fd8322b8c1b70c6653965b15 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 1 Mar 2013 22:32:02 +0100 Subject: [PATCH 836/916] Oops, rotation center should be dynamic --- apps/openmw/mwgui/cursor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 852eea29a..15f61d5b6 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -110,7 +110,7 @@ namespace MWGui mWidget->setImageTexture(texture); MyGUI::ISubWidget* main = mWidget->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + rotatingSubskin->setCenter(MyGUI::IntPoint(mSize.width/2,mSize.height/2)); rotatingSubskin->setAngle(Ogre::Degree(rotation).valueRadians()); } From ccb7ed93b3d231c112b7ab7541178e19cb2adcf3 Mon Sep 17 00:00:00 2001 From: lazydev Date: Sat, 2 Mar 2013 03:54:25 +0400 Subject: [PATCH 837/916] fix for https://bugs.openmw.org/issues/593 --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 6 +++- apps/openmw/mwdialogue/filter.cpp | 34 ++++++++++++++----- apps/openmw/mwdialogue/filter.hpp | 3 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index f548c46f7..43d201fbf 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -251,8 +251,12 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - if (const ESM::DialInfo *info = filter.search (dialogue, true)) + std::vector infos; + filter.search (infos, dialogue, true, true); + if (!infos.empty()) { + const ESM::DialInfo* info = infos[rand() % infos.size()]; + parseText (info->mResponse); if (dialogue.mType==ESM::Dialogue::Persuasion) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 6f9d8b42f..4391716fd 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -559,8 +559,22 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo : mActor (actor), mChoice (choice), mTalkedToPlayer (talkedToPlayer) {} -const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const +const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const { + std::vector suitableInfos; + search(suitableInfos, dialogue, fallbackToInfoRefusal, false); + + if (suitableInfos.empty()) + return NULL; + else + return suitableInfos[0]; +} + +void MWDialogue::Filter::search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, + const bool fallbackToInfoRefusal, bool searchAll) const +{ + suitableInfos.clear(); + bool infoRefusal = false; // Iterate over topic responses to find a matching one @@ -569,14 +583,17 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { - if (testDisposition (*iter)) - return &*iter; + if (testDisposition (*iter)) { + suitableInfos.push_back(&*iter); + if (!searchAll) + return; + } else infoRefusal = true; } } - if (infoRefusal && fallbackToInfoRefusal) + if (suitableInfos.empty() && infoRefusal && fallbackToInfoRefusal) { // No response is valid because of low NPC disposition, // search a response in the topic "Info Refusal" @@ -588,11 +605,12 @@ const ESM::DialInfo *MWDialogue::Filter::search (const ESM::Dialogue& dialogue, for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) - if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) - return &*iter; + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { + suitableInfos.push_back(&*iter); + if (!searchAll) + return; + } } - - return 0; } bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 707c0154b..e1e22a51c 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -51,7 +51,8 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - const ESM::DialInfo *search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; + void search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal, bool searchAll) const; + const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. From e3fd4b842954e31e15e81cd71eb4ad2b5acca69f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 1 Mar 2013 17:57:34 -0800 Subject: [PATCH 838/916] Fix restoring the original texture name when the DDS check fails --- components/nifogre/ogre_nif_loader.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 0b53177e1..d33243dd4 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -621,7 +621,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) // verify, and revert if false (this call succeeds quickly, but fails slowly) if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - texName = path + Misc::StringUtils::lowerCase(texName); + { + texName = st->filename; + Misc::StringUtils::toLower(texName); + if(texName.compare(0, sizeof(path)-1, path) != 0) + texName = path + texName; + } } } else warn("Found internal texture, ignoring."); From 0f4f91605a402f636e45ac81cd45708eab6fa121 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 2 Mar 2013 11:19:48 +0100 Subject: [PATCH 839/916] some cleanup --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 7 ++++--- apps/openmw/mwdialogue/filter.cpp | 21 ++++++++++--------- apps/openmw/mwdialogue/filter.hpp | 6 +++++- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 43d201fbf..35f0c9493 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -2,6 +2,7 @@ #include "dialoguemanagerimp.hpp" #include +#include #include #include @@ -251,11 +252,11 @@ namespace MWDialogue MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - std::vector infos; - filter.search (infos, dialogue, true, true); + std::vector infos = filter.list (dialogue, true, true); + if (!infos.empty()) { - const ESM::DialInfo* info = infos[rand() % infos.size()]; + const ESM::DialInfo* info = infos[std::rand() % infos.size()]; parseText (info->mResponse); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 4391716fd..10740794e 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -561,8 +561,7 @@ MWDialogue::Filter::Filter (const MWWorld::Ptr& actor, int choice, bool talkedTo const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const { - std::vector suitableInfos; - search(suitableInfos, dialogue, fallbackToInfoRefusal, false); + std::vector suitableInfos = list (dialogue, fallbackToInfoRefusal, false); if (suitableInfos.empty()) return NULL; @@ -570,10 +569,10 @@ const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, return suitableInfos[0]; } -void MWDialogue::Filter::search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, - const bool fallbackToInfoRefusal, bool searchAll) const +std::vector MWDialogue::Filter::list (const ESM::Dialogue& dialogue, + bool fallbackToInfoRefusal, bool searchAll) const { - suitableInfos.clear(); + std::vector infos; bool infoRefusal = false; @@ -584,16 +583,16 @@ void MWDialogue::Filter::search (std::vector& suitableInfo if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { if (testDisposition (*iter)) { - suitableInfos.push_back(&*iter); + infos.push_back(&*iter); if (!searchAll) - return; + break; } else infoRefusal = true; } } - if (suitableInfos.empty() && infoRefusal && fallbackToInfoRefusal) + if (infos.empty() && infoRefusal && fallbackToInfoRefusal) { // No response is valid because of low NPC disposition, // search a response in the topic "Info Refusal" @@ -606,11 +605,13 @@ void MWDialogue::Filter::search (std::vector& suitableInfo for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { - suitableInfos.push_back(&*iter); + infos.push_back(&*iter); if (!searchAll) - return; + break; } } + + return infos; } bool MWDialogue::Filter::responseAvailable (const ESM::Dialogue& dialogue) const diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index e1e22a51c..069bf6353 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWDIALOGUE_FILTER_H #define GAME_MWDIALOGUE_FILTER_H +#include + #include "../mwworld/ptr.hpp" namespace ESM @@ -51,7 +53,9 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); - void search (std::vector& suitableInfos, const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal, bool searchAll) const; + std::vector list (const ESM::Dialogue& dialogue, + bool fallbackToInfoRefusal, bool searchAll) const; + const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. /// Redirect to "Info Refusal" topic if a response fulfills all conditions but disposition. From e1957e4ee900b31eabb2f3fb9e90fb89d38d1958 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 2 Mar 2013 13:34:26 +0100 Subject: [PATCH 840/916] Potion effects should be hidden until discovered --- apps/openmw/mwclass/potion.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index c3a6df211..0ac78a2e4 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -20,6 +20,8 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwmechanics/npcstats.hpp" + namespace MWClass { void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -138,6 +140,23 @@ namespace MWClass text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects); + + // hide effects the player doesnt know about + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); + int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase(); + int i=0; + for (MWGui::Widgets::SpellEffectList::iterator it = info.effects.begin(); it != info.effects.end(); ++it) + { + /// \todo this code is duplicated from mwclass/ingredient, put it in a helper function + it->mKnown = ( (i == 0 && alchemySkill >= 15) + || (i == 1 && alchemySkill >= 30) + || (i == 2 && alchemySkill >= 45) + || (i == 3 && alchemySkill >= 60)); + + ++i; + } + info.isPotion = true; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { From 9acd4061ccc2ff497cca8e18baa4052beb073da3 Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 2 Mar 2013 17:04:17 +0100 Subject: [PATCH 841/916] Fix dangling static references in mShared --- apps/openmw/mwworld/store.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 5fad63ff5..52120ed0e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,6 +187,15 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); + // delete from static part of shared + typename std::vector::iterator sharedit = mShared.begin(); + for (; sharedit != (mShared.begin()+mStatic.size()); ++sharedit) { + if((*sharedit)->mId == item.mId) { + mShared.erase(sharedit); + break; + } + } + typename std::map::iterator it = mStatic.find(item.mId); if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { From 6de6d9ff6eabc79236b206a09c710b85ec4135f9 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 13:03:05 -0800 Subject: [PATCH 842/916] Factored a NIFStream class out of the NIFFile class. Split NIFFile into two parts, NIFFile which is cached and is a container for a parsed NIF, and NIFStream which is a class specialized for parsing NIFs. This required a semi-sweeping change to make all record classes accept a NIFStream instead of a NIFFile as an agurment to their read functions. --- components/nif/controlled.hpp | 14 +-- components/nif/controller.hpp | 18 ++-- components/nif/data.hpp | 30 +++--- components/nif/effect.hpp | 6 +- components/nif/extra.hpp | 8 +- components/nif/nif_file.cpp | 15 ++- components/nif/nif_file.hpp | 154 ++---------------------------- components/nif/nif_stream.hpp | 175 ++++++++++++++++++++++++++++++++++ components/nif/node.hpp | 14 +-- components/nif/property.hpp | 16 ++-- components/nif/record.hpp | 3 +- components/nif/record_ptr.hpp | 4 +- 12 files changed, 249 insertions(+), 208 deletions(-) create mode 100644 components/nif/nif_stream.hpp diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index b9d84b58a..dac541b2d 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -36,7 +36,7 @@ class Controlled : public Extra public: ControllerPtr controller; - void read(NIFFile *nif) + void read(NIFStream *nif) { Extra::read(nif); controller.read(nif); @@ -55,7 +55,7 @@ class Named : public Controlled public: std::string name; - void read(NIFFile *nif) + void read(NIFStream *nif) { name = nif->getString(); Controlled::read(nif); @@ -66,7 +66,7 @@ typedef Named NiSequenceStreamHelper; class NiParticleGrowFade : public Controlled { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); @@ -80,7 +80,7 @@ class NiParticleColorModifier : public Controlled public: NiColorDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); data.read(nif); @@ -96,7 +96,7 @@ public: class NiGravity : public Controlled { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); @@ -109,7 +109,7 @@ public: class NiPlanarCollider : public Controlled { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); @@ -121,7 +121,7 @@ public: class NiParticleRotation : public Controlled { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controlled::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index cbc19cd8f..4f7ef3c0f 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -40,7 +40,7 @@ public: float timeStart, timeStop; ControlledPtr target; - void read(NIFFile *nif) + void read(NIFStream *nif) { next.read(nif); @@ -65,7 +65,7 @@ public: class NiBSPArrayController : public Controller { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); @@ -82,7 +82,7 @@ class NiMaterialColorController : public Controller public: NiPosDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); @@ -101,7 +101,7 @@ public: NiPosDataPtr posData; NiFloatDataPtr floatData; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); @@ -129,7 +129,7 @@ class NiUVController : public Controller public: NiUVDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); @@ -149,7 +149,7 @@ class NiKeyframeController : public Controller public: NiKeyframeDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); @@ -167,7 +167,7 @@ class NiAlphaController : public Controller public: NiFloatDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); @@ -185,7 +185,7 @@ class NiGeomMorpherController : public Controller public: NiMorphDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); @@ -204,7 +204,7 @@ class NiVisController : public Controller public: NiVisDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Controller::read(nif); data.read(nif); diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 46b58da8f..5f18800f0 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -65,7 +65,7 @@ public: */ int alpha; - void read(NIFFile *nif) + void read(NIFStream *nif) { Named::read(nif); @@ -102,7 +102,7 @@ public: Ogre::Vector3 center; float radius; - void read(NIFFile *nif) + void read(NIFStream *nif) { int verts = nif->getUShort(); @@ -138,7 +138,7 @@ public: // Triangles, three vertex indices per triangle std::vector triangles; - void read(NIFFile *nif) + void read(NIFStream *nif) { ShapeData::read(nif); @@ -167,7 +167,7 @@ class NiAutoNormalParticlesData : public ShapeData public: int activeCount; - void read(NIFFile *nif) + void read(NIFStream *nif) { ShapeData::read(nif); @@ -189,7 +189,7 @@ public: class NiRotatingParticlesData : public NiAutoNormalParticlesData { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { NiAutoNormalParticlesData::read(nif); @@ -208,7 +208,7 @@ class NiPosData : public Record public: Vector3KeyList mKeyList; - void read(NIFFile *nif) + void read(NIFStream *nif) { mKeyList.read(nif); } @@ -219,7 +219,7 @@ class NiUVData : public Record public: FloatKeyList mKeyList[4]; - void read(NIFFile *nif) + void read(NIFStream *nif) { for(int i = 0;i < 4;i++) mKeyList[i].read(nif); @@ -231,7 +231,7 @@ class NiFloatData : public Record public: FloatKeyList mKeyList; - void read(NIFFile *nif) + void read(NIFStream *nif) { mKeyList.read(nif); } @@ -243,7 +243,7 @@ public: unsigned int rmask, gmask, bmask, amask; int bpp, mips; - void read(NIFFile *nif) + void read(NIFStream *nif) { nif->getInt(); // always 0 or 1 @@ -281,7 +281,7 @@ class NiColorData : public Record public: Vector4KeyList mKeyList; - void read(NIFFile *nif) + void read(NIFStream *nif) { mKeyList.read(nif); } @@ -295,7 +295,7 @@ public: char isSet; }; - void read(NIFFile *nif) + void read(NIFStream *nif) { int count = nif->getInt(); @@ -311,7 +311,7 @@ public: NodePtr root; NodeList bones; - void read(NIFFile *nif) + void read(NIFStream *nif) { data.read(nif); root.read(nif); @@ -347,7 +347,7 @@ public: BoneTrafo trafo; std::vector bones; - void read(NIFFile *nif) + void read(NIFStream *nif) { trafo.rotation = nif->getMatrix3(); trafo.trans = nif->getVector3(); @@ -385,7 +385,7 @@ struct NiMorphData : public Record }; std::vector mMorphs; - void read(NIFFile *nif) + void read(NIFStream *nif) { int morphCount = nif->getInt(); int vertCount = nif->getInt(); @@ -410,7 +410,7 @@ struct NiKeyframeData : public Record Vector3KeyList mTranslations; FloatKeyList mScales; - void read(NIFFile *nif) + void read(NIFStream *nif) { mRotations.read(nif); mTranslations.read(nif); diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 850415dad..b07a39303 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -42,7 +42,7 @@ struct NiLight : Effect Ogre::Vector3 diffuse; Ogre::Vector3 specular; - void read(NIFFile *nif) + void read(NIFStream *nif) { dimmer = nif->getFloat(); ambient = nif->getVector3(); @@ -52,7 +52,7 @@ struct NiLight : Effect }; SLight light; - void read(NIFFile *nif) + void read(NIFStream *nif) { Effect::read(nif); @@ -66,7 +66,7 @@ struct NiTextureEffect : Effect { NiSourceTexturePtr texture; - void read(NIFFile *nif) + void read(NIFStream *nif) { Effect::read(nif); diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index 35781dbf5..b5335f987 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -40,14 +40,14 @@ class Extra : public Record public: ExtraPtr extra; - void read(NIFFile *nif) { extra.read(nif); } + void read(NIFStream *nif) { extra.read(nif); } void post(NIFFile *nif) { extra.post(nif); } }; class NiVertWeightsExtraData : public Extra { public: - void read(NIFFile *nif) + void read(NIFStream *nif) { Extra::read(nif); @@ -70,7 +70,7 @@ public: }; std::vector list; - void read(NIFFile *nif) + void read(NIFStream *nif) { Extra::read(nif); @@ -95,7 +95,7 @@ public: */ std::string string; - void read(NIFFile *nif) + void read(NIFStream *nif) { Extra::read(nif); diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 6e806e7ec..f3faf563c 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -174,10 +174,7 @@ NIFFile::ptr NIFFile::create (const std::string &name) { return LoadedCache::cre NIFFile::NIFFile(const std::string &name, psudo_private_modifier) : filename(name) { - inp = Ogre::ResourceGroupManager::getSingleton().openResource(name); parse(); - // Make sure to close the file after it was loaded into memory - inp.setNull(); } NIFFile::~NIFFile() @@ -195,18 +192,20 @@ NIFFile::~NIFFile() void NIFFile::parse() { + NIFStream nif (this, Ogre::ResourceGroupManager::getSingleton().openResource(filename)); + // Check the header string - std::string head = getString(40); + std::string head = nif.getString(40); if(head.compare(0, 22, "NetImmerse File Format") != 0) fail("Invalid NIF header"); // Get BCD version - ver = getInt(); + ver = nif.getInt(); if(ver != VER_MW) fail("Unsupported NIF version"); // Number of records - size_t recNum = getInt(); + size_t recNum = nif.getInt(); records.resize(recNum); /* The format for 10.0.1.0 seems to be a bit different. After the @@ -222,7 +221,7 @@ void NIFFile::parse() { Record *r = NULL; - std::string rec = getString(); + std::string rec = nif.getString(); /* These are all the record types we know how to read. @@ -312,7 +311,7 @@ void NIFFile::parse() r->recName = rec; r->recIndex = i; records[i] = r; - r->read(this); + r->read(&nif); // Discard tranformations for the root node, otherwise some meshes // occasionally get wrong orientation. Only for NiNode-s for now, but diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index 5e9694f4b..a406de4a0 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -46,6 +46,7 @@ #include "record.hpp" #include "nif_types.hpp" +#include "nif_stream.hpp" namespace Nif { @@ -59,9 +60,6 @@ class NIFFile /// Nif file version int ver; - /// Input stream - Ogre::DataStreamPtr inp; - /// File name, used for error messages std::string filename; @@ -71,33 +69,6 @@ class NIFFile /// Parse the file void parse(); - uint8_t read_byte() - { - uint8_t byte; - if(inp->read(&byte, 1) != 1) return 0; - return byte; - } - uint16_t read_le16() - { - uint8_t buffer[2]; - if(inp->read(buffer, 2) != 2) return 0; - return buffer[0] | (buffer[1]<<8); - } - uint32_t read_le32() - { - uint8_t buffer[4]; - if(inp->read(buffer, 4) != 4) return 0; - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); - } - float read_le32f() - { - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; - } - class LoadedCache; friend class LoadedCache; @@ -117,8 +88,8 @@ public: void warn(const std::string &msg) { - std::cerr<< "NIFFile Warning: "< ptr; @@ -147,111 +118,6 @@ public: /// Number of records size_t numRecords() { return records.size(); } - - /************************************************* - Parser functions - ****************************************************/ - - void skip(size_t size) { inp->skip(size); } - - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - unsigned int getUInt() { return read_le32(); } - float getFloat() { return read_le32f(); } - Ogre::Vector2 getVector2() - { - float a[2]; - for(size_t i = 0;i < 2;i++) - a[i] = getFloat(); - return Ogre::Vector2(a); - } - Ogre::Vector3 getVector3() - { - float a[3]; - for(size_t i = 0;i < 3;i++) - a[i] = getFloat(); - return Ogre::Vector3(a); - } - Ogre::Vector4 getVector4() - { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Vector4(a); - } - Ogre::Matrix3 getMatrix3() - { - Ogre::Real a[3][3]; - for(size_t i = 0;i < 3;i++) - { - for(size_t j = 0;j < 3;j++) - a[i][j] = Ogre::Real(getFloat()); - } - return Ogre::Matrix3(a); - } - Ogre::Quaternion getQuaternion() - { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Quaternion(a); - } - Transformation getTrafo() - { - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; - } - - std::string getString(size_t length) - { - std::vector str (length+1, 0); - - if(inp->read(&str[0], length) != length) - throw std::runtime_error ("string length in NIF file does not match"); - - return &str[0]; - } - std::string getString() - { - size_t size = read_le32(); - return getString(size); - } - - void getShorts(std::vector &vec, size_t size) - { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); - } - void getFloats(std::vector &vec, size_t size) - { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); - } - void getVector2s(std::vector &vec, size_t size) - { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); - } - void getVector3s(std::vector &vec, size_t size) - { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); - } - void getVector4s(std::vector &vec, size_t size) - { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); - } }; @@ -270,7 +136,7 @@ typedef KeyT Vector3Key; typedef KeyT Vector4Key; typedef KeyT QuaternionKey; -template +template struct KeyListT { typedef std::vector< KeyT > VecType; @@ -281,7 +147,7 @@ struct KeyListT { int mInterpolationType; VecType mKeys; - void read(NIFFile *nif, bool force=false) + void read(NIFStream *nif, bool force=false) { size_t count = nif->getInt(); if(count == 0 && !force) @@ -322,13 +188,13 @@ struct KeyListT { } } else - nif->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); } }; -typedef KeyListT FloatKeyList; -typedef KeyListT Vector3KeyList; -typedef KeyListT Vector4KeyList; -typedef KeyListT QuaternionKeyList; +typedef KeyListT FloatKeyList; +typedef KeyListT Vector3KeyList; +typedef KeyListT Vector4KeyList; +typedef KeyListT QuaternionKeyList; } // Namespace #endif diff --git a/components/nif/nif_stream.hpp b/components/nif/nif_stream.hpp new file mode 100644 index 000000000..8fb98f3d6 --- /dev/null +++ b/components/nif/nif_stream.hpp @@ -0,0 +1,175 @@ +#ifndef _NIF_STREAM_HPP_ +#define _NIF_STREAM_HPP_ + +namespace Nif +{ + +class NIFFile; + +class NIFStream { + + /// Input stream + Ogre::DataStreamPtr inp; + + uint8_t read_byte() + { + uint8_t byte; + if(inp->read(&byte, 1) != 1) return 0; + return byte; + } + uint16_t read_le16() + { + uint8_t buffer[2]; + if(inp->read(buffer, 2) != 2) return 0; + return buffer[0] | (buffer[1]<<8); + } + uint32_t read_le32() + { + uint8_t buffer[4]; + if(inp->read(buffer, 4) != 4) return 0; + return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); + } + float read_le32f() + { + union { + uint32_t i; + float f; + } u = { read_le32() }; + return u.f; + } + +public: + + NIFFile * const file; + + NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + + /************************************************* + Parser functions + ****************************************************/ + + template + struct GetHandler + { + typedef T (NIFStream::*fn_t)(); + + static const fn_t sValue; // this is specialized per supported type in the .cpp file + + static T read (NIFStream* nif) + { + return (nif->*sValue) (); + } + }; + + template + void read (NIFStream* nif, T & Value) + { + Value = GetHandler ::read (nif); + } + + void skip(size_t size) { inp->skip(size); } + void read (void * data, size_t size) { inp->read (data, size); } + + char getChar() { return read_byte(); } + short getShort() { return read_le16(); } + unsigned short getUShort() { return read_le16(); } + int getInt() { return read_le32(); } + int getUInt() { return read_le32(); } + float getFloat() { return read_le32f(); } + Ogre::Vector2 getVector2() + { + float a[2]; + for(size_t i = 0;i < 2;i++) + a[i] = getFloat(); + return Ogre::Vector2(a); + } + Ogre::Vector3 getVector3() + { + float a[3]; + for(size_t i = 0;i < 3;i++) + a[i] = getFloat(); + return Ogre::Vector3(a); + } + Ogre::Vector4 getVector4() + { + float a[4]; + for(size_t i = 0;i < 4;i++) + a[i] = getFloat(); + return Ogre::Vector4(a); + } + Ogre::Matrix3 getMatrix3() + { + Ogre::Real a[3][3]; + for(size_t i = 0;i < 3;i++) + { + for(size_t j = 0;j < 3;j++) + a[i][j] = Ogre::Real(getFloat()); + } + return Ogre::Matrix3(a); + } + Ogre::Quaternion getQuaternion() + { + float a[4]; + for(size_t i = 0;i < 4;i++) + a[i] = getFloat(); + return Ogre::Quaternion(a); + } + Transformation getTrafo() + { + Transformation t; + t.pos = getVector3(); + t.rotation = getMatrix3(); + t.scale = getFloat(); + return t; + } + + std::string getString(size_t length) + { + std::vector str (length+1, 0); + + if(inp->read(&str[0], length) != length) + throw std::runtime_error ("string length in NIF file does not match"); + + return &str[0]; + } + std::string getString() + { + size_t size = read_le32(); + return getString(size); + } + + void getShorts(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getShort(); + } + void getFloats(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getFloat(); + } + void getVector2s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector2(); + } + void getVector3s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector3(); + } + void getVector4s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector4(); + } +}; + +} + +#endif diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 07e7868cc..e08703756 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -54,7 +54,7 @@ public: Ogre::Matrix3 boundRot; Ogre::Vector3 boundXYZ; // Box size - void read(NIFFile *nif) + void read(NIFStream *nif) { Named::read(nif); @@ -128,7 +128,7 @@ struct NiNode : Node 0x20, 0x40, 0x80 unknown */ - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); children.read(nif); @@ -162,7 +162,7 @@ struct NiTriShape : Node NiTriShapeDataPtr data; NiSkinInstancePtr skin; - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); data.read(nif); @@ -190,7 +190,7 @@ struct NiCamera : Node // Level of detail modifier float LOD; - void read(NIFFile *nif) + void read(NIFStream *nif) { left = nif->getFloat(); right = nif->getFloat(); @@ -209,7 +209,7 @@ struct NiCamera : Node }; Camera cam; - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); @@ -224,7 +224,7 @@ struct NiAutoNormalParticles : Node { NiAutoNormalParticlesDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); data.read(nif); @@ -242,7 +242,7 @@ struct NiRotatingParticles : Node { NiRotatingParticlesDataPtr data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Node::read(nif); data.read(nif); diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 046fb0465..cdf97986c 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -35,7 +35,7 @@ public: // The meaning of these depends on the actual property type. int flags; - void read(NIFFile *nif) + void read(NIFStream *nif) { Named::read(nif); flags = nif->getUShort(); @@ -67,7 +67,7 @@ public: int clamp, set, filter; short unknown2; - void read(NIFFile *nif) + void read(NIFStream *nif) { inUse = !!nif->getInt(); if(!inUse) return; @@ -111,7 +111,7 @@ public: */ Texture textures[7]; - void read(NIFFile *nif) + void read(NIFStream *nif) { Property::read(nif); apply = nif->getInt(); @@ -157,7 +157,7 @@ struct StructPropT : Property { T data; - void read(NIFFile *nif) + void read(NIFStream *nif) { Property::read(nif); data.read(nif); @@ -170,7 +170,7 @@ struct S_MaterialProperty Ogre::Vector3 ambient, diffuse, specular, emissive; float glossiness, alpha; - void read(NIFFile *nif) + void read(NIFStream *nif) { ambient = nif->getVector3(); diffuse = nif->getVector3(); @@ -194,7 +194,7 @@ struct S_VertexColorProperty */ int vertmode, lightmode; - void read(NIFFile *nif) + void read(NIFStream *nif) { vertmode = nif->getInt(); lightmode = nif->getInt(); @@ -251,7 +251,7 @@ struct S_AlphaProperty // Tested against when certain flags are set (see above.) unsigned char threshold; - void read(NIFFile *nif) + void read(NIFStream *nif) { threshold = nif->getChar(); } @@ -300,7 +300,7 @@ struct S_StencilProperty */ int drawMode; - void read(NIFFile *nif) + void read(NIFStream *nif) { enabled = nif->getChar(); compareFunc = nif->getInt(); diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 073f4657c..9f0645dfd 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -30,6 +30,7 @@ namespace Nif { class NIFFile; +class NIFStream; enum RecordType { @@ -97,7 +98,7 @@ struct Record Record() : recType(RC_MISSING), recIndex(~(size_t)0) {} /// Parses the record from file - virtual void read(NIFFile *nif) = 0; + virtual void read(NIFStream *nif) = 0; /// Does post-processing, after the entire tree is loaded virtual void post(NIFFile *nif) {} diff --git a/components/nif/record_ptr.hpp b/components/nif/record_ptr.hpp index ef5bb1dee..855099a04 100644 --- a/components/nif/record_ptr.hpp +++ b/components/nif/record_ptr.hpp @@ -46,7 +46,7 @@ public: RecordPtrT() : index(-2) {} /// Read the index from the nif - void read(NIFFile *nif) + void read(NIFStream *nif) { // Can only read the index once assert(index == -2); @@ -99,7 +99,7 @@ class RecordListT std::vector list; public: - void read(NIFFile *nif) + void read(NIFStream *nif) { int len = nif->getInt(); list.resize(len); From 0ed2015319a0afa2c59a393e7e876572af419134 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 3 Jan 2013 23:59:32 -0800 Subject: [PATCH 843/916] refactored NIFFile parse to get better code/data seperation --- components/nif/nif_file.cpp | 182 ++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 80 deletions(-) diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index f3faf563c..dc8670cba 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -185,6 +185,101 @@ NIFFile::~NIFFile() delete records[i]; } +template static Record* construct() { return new NodeType; } + +struct RecordFactoryEntry { + + typedef Record* (*create_t) (); + + char const * mName; + create_t mCreate; + RecordType mType; + +}; + +/* These are all the record types we know how to read. + + This can be heavily optimized later if needed. For example, a + hash table or a FSM-based parser could be used to look up + node names. +*/ + +static const RecordFactoryEntry recordFactories [] = { + + { "NiNode", &construct , RC_NiNode }, + { "AvoidNode", &construct , RC_NiNode }, + { "NiBSParticleNode", &construct , RC_NiNode }, + { "NiBSAnimationNode", &construct , RC_NiNode }, + { "NiBillboardNode", &construct , RC_NiNode }, + { "NiTriShape", &construct , RC_NiTriShape }, + { "NiRotatingParticles", &construct , RC_NiRotatingParticles }, + { "NiAutoNormalParticles", &construct , RC_NiAutoNormalParticles }, + { "NiCamera", &construct , RC_NiCamera }, + { "RootCollisionNode", &construct , RC_RootCollisionNode }, + { "NiTexturingProperty", &construct , RC_NiTexturingProperty }, + { "NiMaterialProperty", &construct , RC_NiMaterialProperty }, + { "NiZBufferProperty", &construct , RC_NiZBufferProperty }, + { "NiAlphaProperty", &construct , RC_NiAlphaProperty }, + { "NiVertexColorProperty", &construct , RC_NiVertexColorProperty }, + { "NiShadeProperty", &construct , RC_NiShadeProperty }, + { "NiDitherProperty", &construct , RC_NiDitherProperty }, + { "NiWireframeProperty", &construct , RC_NiWireframeProperty }, + { "NiSpecularProperty", &construct , RC_NiSpecularProperty }, + { "NiStencilProperty", &construct , RC_NiStencilProperty }, + { "NiVisController", &construct , RC_NiVisController }, + { "NiGeomMorpherController", &construct , RC_NiGeomMorpherController }, + { "NiKeyframeController", &construct , RC_NiKeyframeController }, + { "NiAlphaController", &construct , RC_NiAlphaController }, + { "NiUVController", &construct , RC_NiUVController }, + { "NiPathController", &construct , RC_NiPathController }, + { "NiMaterialColorController", &construct , RC_NiMaterialColorController }, + { "NiBSPArrayController", &construct , RC_NiBSPArrayController }, + { "NiParticleSystemController", &construct , RC_NiParticleSystemController }, + { "NiAmbientLight", &construct , RC_NiLight }, + { "NiDirectionalLight", &construct , RC_NiLight }, + { "NiTextureEffect", &construct , RC_NiTextureEffect }, + { "NiVertWeightsExtraData", &construct , RC_NiVertWeightsExtraData }, + { "NiTextKeyExtraData", &construct , RC_NiTextKeyExtraData }, + { "NiStringExtraData", &construct , RC_NiStringExtraData }, + { "NiGravity", &construct , RC_NiGravity }, + { "NiPlanarCollider", &construct , RC_NiPlanarCollider }, + { "NiParticleGrowFade", &construct , RC_NiParticleGrowFade }, + { "NiParticleColorModifier", &construct , RC_NiParticleColorModifier }, + { "NiParticleRotation", &construct , RC_NiParticleRotation }, + { "NiFloatData", &construct , RC_NiFloatData }, + { "NiTriShapeData", &construct , RC_NiTriShapeData }, + { "NiVisData", &construct , RC_NiVisData }, + { "NiColorData", &construct , RC_NiColorData }, + { "NiPixelData", &construct , RC_NiPixelData }, + { "NiMorphData", &construct , RC_NiMorphData }, + { "NiKeyframeData", &construct , RC_NiKeyframeData }, + { "NiSkinData", &construct , RC_NiSkinData }, + { "NiUVData", &construct , RC_NiUVData }, + { "NiPosData", &construct , RC_NiPosData }, + { "NiRotatingParticlesData", &construct , RC_NiRotatingParticlesData }, + { "NiAutoNormalParticlesData", &construct , RC_NiAutoNormalParticlesData }, + { "NiSequenceStreamHelper", &construct , RC_NiSequenceStreamHelper }, + { "NiSourceTexture", &construct , RC_NiSourceTexture }, + { "NiSkinInstance", &construct , RC_NiSkinInstance }, +}; + +static RecordFactoryEntry const * recordFactories_begin = &recordFactories [0]; +static RecordFactoryEntry const * recordFactories_end = &recordFactories [sizeof (recordFactories) / sizeof (recordFactories[0])]; + +RecordFactoryEntry const * lookupRecordFactory (char const * name) +{ + RecordFactoryEntry const * i; + + for (i = recordFactories_begin; i != recordFactories_end; ++i) + if (strcmp (name, i->mName) == 0) + break; + + if (i == recordFactories_end) + return NULL; + + return i; +} + /* This file implements functions from the NIFFile class. It is also where we stash all the functions we couldn't add as inline definitions in the record types. @@ -223,88 +318,15 @@ void NIFFile::parse() std::string rec = nif.getString(); - /* These are all the record types we know how to read. + RecordFactoryEntry const * entry = lookupRecordFactory (rec.c_str ()); - This can be heavily optimized later if needed. For example, a - hash table or a FSM-based parser could be used to look up - node names. - */ - - // NiNodes - if(rec == "NiNode" || rec == "AvoidNode" || - rec == "NiBSParticleNode" || - rec == "NiBSAnimationNode" || - rec == "NiBillboardNode") { r = new NiNode; r->recType = RC_NiNode; } - - // Other nodes - else if(rec == "NiTriShape") { r = new NiTriShape; r->recType = RC_NiTriShape; } - else if(rec == "NiRotatingParticles") { r = new NiRotatingParticles; r->recType = RC_NiRotatingParticles; } - else if(rec == "NiAutoNormalParticles") { r = new NiAutoNormalParticles; r->recType = RC_NiAutoNormalParticles; } - else if(rec == "NiCamera") { r = new NiCamera; r->recType = RC_NiCamera; } - else if(rec == "RootCollisionNode"){ r = new NiNode; r->recType = RC_RootCollisionNode; }// a root collision node is exactly like a node - //that's why there is no need to create a new type - - // Properties - else if(rec == "NiTexturingProperty") { r = new NiTexturingProperty; r->recType = RC_NiTexturingProperty; } - else if(rec == "NiMaterialProperty") { r = new NiMaterialProperty; r->recType = RC_NiMaterialProperty; } - else if(rec == "NiZBufferProperty") { r = new NiZBufferProperty; r->recType = RC_NiZBufferProperty; } - else if(rec == "NiAlphaProperty") { r = new NiAlphaProperty; r->recType = RC_NiAlphaProperty; } - else if(rec == "NiVertexColorProperty") { r = new NiVertexColorProperty; r->recType = RC_NiVertexColorProperty; } - else if(rec == "NiShadeProperty") { r = new NiShadeProperty; r->recType = RC_NiShadeProperty; } - else if(rec == "NiDitherProperty") { r = new NiDitherProperty; r->recType = RC_NiDitherProperty; } - else if(rec == "NiWireframeProperty") { r = new NiWireframeProperty; r->recType = RC_NiWireframeProperty; } - else if(rec == "NiSpecularProperty") { r = new NiSpecularProperty; r->recType = RC_NiSpecularProperty; } - else if(rec == "NiStencilProperty") { r = new NiStencilProperty; r->recType = RC_NiStencilProperty; } - - // Controllers - else if(rec == "NiVisController") { r = new NiVisController; r->recType = RC_NiVisController; } - else if(rec == "NiGeomMorpherController") { r = new NiGeomMorpherController; r->recType = RC_NiGeomMorpherController; } - else if(rec == "NiKeyframeController") { r = new NiKeyframeController; r->recType = RC_NiKeyframeController; } - else if(rec == "NiAlphaController") { r = new NiAlphaController; r->recType = RC_NiAlphaController; } - else if(rec == "NiUVController") { r = new NiUVController; r->recType = RC_NiUVController; } - else if(rec == "NiPathController") { r = new NiPathController; r->recType = RC_NiPathController; } - else if(rec == "NiMaterialColorController") { r = new NiMaterialColorController; r->recType = RC_NiMaterialColorController; } - else if(rec == "NiBSPArrayController") { r = new NiBSPArrayController; r->recType = RC_NiBSPArrayController; } - else if(rec == "NiParticleSystemController") { r = new NiParticleSystemController; r->recType = RC_NiParticleSystemController; } - - // Effects - else if(rec == "NiAmbientLight" || - rec == "NiDirectionalLight") { r = new NiLight; r->recType = RC_NiLight; } - else if(rec == "NiTextureEffect") { r = new NiTextureEffect; r->recType = RC_NiTextureEffect; } - - // Extra Data - else if(rec == "NiVertWeightsExtraData") { r = new NiVertWeightsExtraData; r->recType = RC_NiVertWeightsExtraData; } - else if(rec == "NiTextKeyExtraData") { r = new NiTextKeyExtraData; r->recType = RC_NiTextKeyExtraData; } - else if(rec == "NiStringExtraData") { r = new NiStringExtraData; r->recType = RC_NiStringExtraData; } - - else if(rec == "NiGravity") { r = new NiGravity; r->recType = RC_NiGravity; } - else if(rec == "NiPlanarCollider") { r = new NiPlanarCollider; r->recType = RC_NiPlanarCollider; } - else if(rec == "NiParticleGrowFade") { r = new NiParticleGrowFade; r->recType = RC_NiParticleGrowFade; } - else if(rec == "NiParticleColorModifier") { r = new NiParticleColorModifier; r->recType = RC_NiParticleColorModifier; } - else if(rec == "NiParticleRotation") { r = new NiParticleRotation; r->recType = RC_NiParticleRotation; } - - // Data - else if(rec == "NiFloatData") { r = new NiFloatData; r->recType = RC_NiFloatData; } - else if(rec == "NiTriShapeData") { r = new NiTriShapeData; r->recType = RC_NiTriShapeData; } - else if(rec == "NiVisData") { r = new NiVisData; r->recType = RC_NiVisData; } - else if(rec == "NiColorData") { r = new NiColorData; r->recType = RC_NiColorData; } - else if(rec == "NiPixelData") { r = new NiPixelData; r->recType = RC_NiPixelData; } - else if(rec == "NiMorphData") { r = new NiMorphData; r->recType = RC_NiMorphData; } - else if(rec == "NiKeyframeData") { r = new NiKeyframeData; r->recType = RC_NiKeyframeData; } - else if(rec == "NiSkinData") { r = new NiSkinData; r->recType = RC_NiSkinData; } - else if(rec == "NiUVData") { r = new NiUVData; r->recType = RC_NiUVData; } - else if(rec == "NiPosData") { r = new NiPosData; r->recType = RC_NiPosData; } - else if(rec == "NiRotatingParticlesData") { r = new NiRotatingParticlesData; r->recType = RC_NiRotatingParticlesData; } - else if(rec == "NiAutoNormalParticlesData") { r = new NiAutoNormalParticlesData; r->recType = RC_NiAutoNormalParticlesData; } - - // Other - else if(rec == "NiSequenceStreamHelper") { r = new NiSequenceStreamHelper; r->recType = RC_NiSequenceStreamHelper; } - else if(rec == "NiSourceTexture") { r = new NiSourceTexture; r->recType = RC_NiSourceTexture; } - else if(rec == "NiSkinInstance") { r = new NiSkinInstance; r->recType = RC_NiSkinInstance; } - - // Failure + if (entry != NULL) + { + r = entry->mCreate (); + r->recType = entry->mType; + } else - fail("Unknown record type " + rec); + fail("Unknown record type " + rec); assert(r != NULL); assert(r->recType != RC_MISSING); From d3c1f5e7b23bcfb30fb418b9f0acb18bcfa273a9 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 24 Feb 2013 13:51:56 -0800 Subject: [PATCH 844/916] renamed low-level NIF related files and include guards to conform to naming convention --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwworld/scene.cpp | 2 +- components/CMakeLists.txt | 2 +- components/nif/controlled.hpp | 4 ++-- components/nif/controller.hpp | 8 ++++---- components/nif/data.hpp | 4 ++-- components/nif/effect.hpp | 4 ++-- components/nif/extra.hpp | 8 ++++---- components/nif/{nif_file.cpp => niffile.cpp} | 2 +- components/nif/{nif_file.hpp => niffile.hpp} | 8 ++++---- components/nif/{nif_stream.hpp => nifstream.hpp} | 4 ++-- components/nif/{nif_types.hpp => niftypes.hpp} | 4 ++-- components/nif/node.hpp | 4 ++-- components/nif/property.hpp | 4 ++-- components/nif/record.hpp | 4 ++-- components/nif/{record_ptr.hpp => recordptr.hpp} | 6 +++--- components/nifbullet/bullet_nif_loader.cpp | 2 +- 17 files changed, 36 insertions(+), 36 deletions(-) rename components/nif/{nif_file.cpp => niffile.cpp} (99%) rename components/nif/{nif_file.hpp => niffile.hpp} (97%) rename components/nif/{nif_stream.hpp => nifstream.hpp} (97%) rename components/nif/{nif_types.hpp => niftypes.hpp} (93%) rename components/nif/{record_ptr.hpp => recordptr.hpp} (97%) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d14696cdd..a69dc7402 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index ecf783d6c..35024b307 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,6 +1,6 @@ #include "scene.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" /// FIXME diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00342e2ac..a80afdd6b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -15,7 +15,7 @@ add_component_dir (bsa ) add_component_dir (nif - controlled effect nif_types record controller extra node record_ptr data nif_file property + controlled effect niftypes record controller extra node record_ptr data niffile property ) add_component_dir (nifogre diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index dac541b2d..36c9a82ac 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_CONTROLLED_H_ -#define _NIF_CONTROLLED_H_ +#ifndef OPENMW_COMPONENTS_NIF_CONTROLLED_HPP +#define OPENMW_COMPONENTS_NIF_CONTROLLED_HPP #include "extra.hpp" #include "controller.hpp" diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 4f7ef3c0f..8331b93b7 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -21,12 +21,12 @@ */ -#ifndef _NIF_CONTROLLER_H_ -#define _NIF_CONTROLLER_H_ +#ifndef OPENMW_COMPONENTS_NIF_CONTROLLER_HPP +#define OPENMW_COMPONENTS_NIF_CONTROLLER_HPP #include "record.hpp" -#include "nif_file.hpp" -#include "record_ptr.hpp" +#include "niffile.hpp" +#include "recordptr.hpp" namespace Nif { diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 5f18800f0..9bdba6396 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_DATA_H_ -#define _NIF_DATA_H_ +#ifndef OPENMW_COMPONENTS_NIF_DATA_HPP +#define OPENMW_COMPONENTS_NIF_DATA_HPP #include "controlled.hpp" diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index b07a39303..cc1b0f41c 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_EFFECT_H_ -#define _NIF_EFFECT_H_ +#ifndef OPENMW_COMPONENTS_NIF_EFFECT_HPP +#define OPENMW_COMPONENTS_NIF_EFFECT_HPP #include "node.hpp" diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index b5335f987..45c4fefc6 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -21,12 +21,12 @@ */ -#ifndef _NIF_EXTRA_H_ -#define _NIF_EXTRA_H_ +#ifndef OPENMW_COMPONENTS_NIF_EXTRA_HPP +#define OPENMW_COMPONENTS_NIF_EXTRA_HPP #include "record.hpp" -#include "nif_file.hpp" -#include "record_ptr.hpp" +#include "niffile.hpp" +#include "recordptr.hpp" namespace Nif { diff --git a/components/nif/nif_file.cpp b/components/nif/niffile.cpp similarity index 99% rename from components/nif/nif_file.cpp rename to components/nif/niffile.cpp index dc8670cba..bf05e7576 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/niffile.cpp @@ -21,7 +21,7 @@ */ -#include "nif_file.hpp" +#include "niffile.hpp" #include "record.hpp" #include "components/misc/stringops.hpp" diff --git a/components/nif/nif_file.hpp b/components/nif/niffile.hpp similarity index 97% rename from components/nif/nif_file.hpp rename to components/nif/niffile.hpp index a406de4a0..ed11bdd7c 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/niffile.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_FILE_H_ -#define _NIF_FILE_H_ +#ifndef OPENMW_COMPONENTS_NIF_NIFFILE_HPP +#define OPENMW_COMPONENTS_NIF_NIFFILE_HPP #include #include @@ -45,8 +45,8 @@ #include #include "record.hpp" -#include "nif_types.hpp" -#include "nif_stream.hpp" +#include "niftypes.hpp" +#include "nifstream.hpp" namespace Nif { diff --git a/components/nif/nif_stream.hpp b/components/nif/nifstream.hpp similarity index 97% rename from components/nif/nif_stream.hpp rename to components/nif/nifstream.hpp index 8fb98f3d6..02b931b7e 100644 --- a/components/nif/nif_stream.hpp +++ b/components/nif/nifstream.hpp @@ -1,5 +1,5 @@ -#ifndef _NIF_STREAM_HPP_ -#define _NIF_STREAM_HPP_ +#ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP +#define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP namespace Nif { diff --git a/components/nif/nif_types.hpp b/components/nif/niftypes.hpp similarity index 93% rename from components/nif/nif_types.hpp rename to components/nif/niftypes.hpp index a5fb61361..786c48b65 100644 --- a/components/nif/nif_types.hpp +++ b/components/nif/niftypes.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_TYPES_H_ -#define _NIF_TYPES_H_ +#ifndef OPENMW_COMPONENTS_NIF_NIFTYPES_HPP +#define OPENMW_COMPONENTS_NIF_NIFTYPES_HPP #include #include diff --git a/components/nif/node.hpp b/components/nif/node.hpp index e08703756..ab92d74f8 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_NODE_H_ -#define _NIF_NODE_H_ +#ifndef OPENMW_COMPONENTS_NIF_NODE_HPP +#define OPENMW_COMPONENTS_NIF_NODE_HPP #include diff --git a/components/nif/property.hpp b/components/nif/property.hpp index cdf97986c..cd1e0a5d1 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_PROPERTY_H_ -#define _NIF_PROPERTY_H_ +#ifndef OPENMW_COMPONENTS_NIF_PROPERTY_HPP +#define OPENMW_COMPONENTS_NIF_PROPERTY_HPP #include "controlled.hpp" diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 9f0645dfd..3a3cd9b84 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -21,8 +21,8 @@ */ -#ifndef _NIF_RECORD_H_ -#define _NIF_RECORD_H_ +#ifndef OPENMW_COMPONENTS_NIF_RECORD_HPP +#define OPENMW_COMPONENTS_NIF_RECORD_HPP #include diff --git a/components/nif/record_ptr.hpp b/components/nif/recordptr.hpp similarity index 97% rename from components/nif/record_ptr.hpp rename to components/nif/recordptr.hpp index 855099a04..c5bafea12 100644 --- a/components/nif/record_ptr.hpp +++ b/components/nif/recordptr.hpp @@ -21,10 +21,10 @@ */ -#ifndef _NIF_RECORD_PTR_H_ -#define _NIF_RECORD_PTR_H_ +#ifndef OPENMW_COMPONENTS_NIF_RECORDPTR_HPP +#define OPENMW_COMPONENTS_NIF_RECORDPTR_HPP -#include "nif_file.hpp" +#include "niffile.hpp" #include namespace Nif diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 3d9c16ebb..e33754264 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -25,7 +25,7 @@ http://www.gnu.org/licenses/ . #include #include -#include "../nif/nif_file.hpp" +#include "../nif/niffile.hpp" #include "../nif/node.hpp" #include "../nif/data.hpp" #include "../nif/property.hpp" From fdfcd5bb4774e6a03fef5afafc5f116a635015cd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 12:23:29 -0800 Subject: [PATCH 845/916] Material properties are accumulative along the node tree --- components/nifogre/ogre_nif_loader.cpp | 101 +++++++++++++------------ 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index d33243dd4..1d9c4d748 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -549,7 +549,10 @@ static void fail(const std::string &msg) public: -static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group) +static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -568,36 +571,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String bool vertexColour = (shape->data->colors.size() != 0); - // These are set below if present - const Nif::NiTexturingProperty *t = NULL; - const Nif::NiMaterialProperty *m = NULL; - const Nif::NiAlphaProperty *a = NULL; - - // Scan the property list for material information - const Nif::PropertyList &list = shape->props; - for (size_t i = 0;i < list.length();i++) - { - // Entries may be empty - if (list[i].empty()) continue; - - const Nif::Property *pr = list[i].getPtr(); - if (pr->recType == Nif::RC_NiTexturingProperty) - t = static_cast(pr); - else if (pr->recType == Nif::RC_NiMaterialProperty) - m = static_cast(pr); - else if (pr->recType == Nif::RC_NiAlphaProperty) - a = static_cast(pr); - else if (pr->recType == Nif::RC_NiStencilProperty) - /* unused */; - else - warn("Skipped property type: "+pr->recName); - } - // Texture - if (t && t->textures[0].inUse) + if(texprop && texprop->textures[0].inUse) { - Nif::NiSourceTexture *st = t->textures[0].texture.getPtr(); - if (st->external) + const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); + if(st->external) { /* Bethesda at some point converted all their BSA * textures from tga to dds for increased load speed, but all @@ -633,25 +611,25 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String } // Alpha modifiers - if (a) + if(alphaprop) { - alphaFlags = a->flags; - alphaTest = a->data.threshold; + alphaFlags = alphaprop->flags; + alphaTest = alphaprop->data.threshold; } // Material - if(m) + if(matprop) { - ambient = m->data.ambient; - diffuse = m->data.diffuse; - specular = m->data.specular; - emissive = m->data.emissive; - glossiness = m->data.glossiness; - alpha = m->data.alpha; + ambient = matprop->data.ambient; + diffuse = matprop->data.diffuse; + specular = matprop->data.specular; + emissive = matprop->data.emissive; + glossiness = matprop->data.glossiness; + alpha = matprop->data.alpha; } Ogre::String matname = name; - if (m || !texName.empty()) + if(matprop || !texName.empty()) { // Generate a hash out of all properties that can affect the material. size_t h = 0; @@ -749,7 +727,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mName; std::string mGroup; size_t mShapeIndex; - std::string mMaterialName; void warn(const std::string &msg) { @@ -764,7 +741,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape, + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -962,15 +942,39 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - if(mMaterialName.length() > 0) - sub->setMaterialName(mMaterialName); + std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, + texprop, matprop, alphaprop); + if(matname.length() > 0) + sub->setMaterialName(matname); } - bool findTriShape(Ogre::Mesh *mesh, Nif::Node const *node) + bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, + const Nif::NiTexturingProperty *texprop=NULL, + const Nif::NiMaterialProperty *matprop=NULL, + const Nif::NiAlphaProperty *alphaprop=NULL) { + // Scan the property list for material information + const Nif::PropertyList &proplist = node->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node)); + handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop); return true; } @@ -982,7 +986,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr())) + if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop)) return true; } } @@ -1015,7 +1019,7 @@ public: return; } - Nif::Node const *node = dynamic_cast(nif->getRecord(mShapeIndex)); + const Nif::Node *node = dynamic_cast(nif->getRecord(0)); findTriShape(mesh, node); } @@ -1066,7 +1070,6 @@ public: NIFMeshLoader *loader = &sLoaders[fullname]; *loader = *this; loader->mShapeIndex = shape->recIndex; - loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); From dde43e8c87430c98e52e4aa88186a57ebdde9620 Mon Sep 17 00:00:00 2001 From: k1ll Date: Sat, 2 Mar 2013 21:46:31 +0100 Subject: [PATCH 846/916] Some cleanup --- apps/openmw/mwworld/store.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 52120ed0e..586e407ff 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -187,11 +187,11 @@ namespace MWWorld T item; item.mId = Misc::StringUtils::lowerCase(id); - // delete from static part of shared - typename std::vector::iterator sharedit = mShared.begin(); - for (; sharedit != (mShared.begin()+mStatic.size()); ++sharedit) { - if((*sharedit)->mId == item.mId) { - mShared.erase(sharedit); + // delete from the static part of mShared + typename std::vector::iterator sharedIter = mShared.begin(); + for (; sharedIter != (mShared.begin()+mStatic.size()); ++sharedIter) { + if((*sharedIter)->mId == item.mId) { + mShared.erase(sharedIter); break; } } From 109dff2d29f1ed3b71c4169f917f390043278b46 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 24 Feb 2013 13:52:23 -0800 Subject: [PATCH 847/916] renamed high level NIF files... --- apps/openmw/engine.cpp | 4 ++-- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/objects.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 2 +- apps/openmw/mwworld/physicssystem.cpp | 2 +- components/CMakeLists.txt | 4 ++-- .../nifbullet/{bullet_nif_loader.cpp => bulletnifloader.cpp} | 2 +- .../nifbullet/{bullet_nif_loader.hpp => bulletnifloader.hpp} | 4 ++-- components/nifogre/{ogre_nif_loader.cpp => ogrenifloader.cpp} | 2 +- components/nifogre/{ogre_nif_loader.hpp => ogrenifloader.hpp} | 4 ++-- components/nifoverrides/nifoverrides.hpp | 4 ++-- libs/openengine/bullet/CMotionState.cpp | 2 +- libs/openengine/bullet/physic.cpp | 2 +- 13 files changed, 18 insertions(+), 18 deletions(-) rename components/nifbullet/{bullet_nif_loader.cpp => bulletnifloader.cpp} (99%) rename components/nifbullet/{bullet_nif_loader.hpp => bulletnifloader.hpp} (96%) rename components/nifogre/{ogre_nif_loader.cpp => ogrenifloader.cpp} (99%) rename components/nifogre/{ogre_nif_loader.hpp => ogrenifloader.hpp} (96%) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index a69dc7402..74e967d8d 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include #include "mwinput/inputmanagerimp.hpp" diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 810ca869f..7caf35169 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,7 +1,7 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H -#include +#include #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index e91180a42..89425e9f2 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 062079693..0f778511d 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -14,7 +14,7 @@ #include -#include +#include #include diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 65cbc1164..566a463b6 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include //#include "../mwbase/world.hpp" // FIXME #include "../mwbase/environment.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a80afdd6b..9fdc72873 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,11 +19,11 @@ add_component_dir (nif ) add_component_dir (nifogre - ogre_nif_loader + ogrenifloader ) add_component_dir (nifbullet - bullet_nif_loader + bulletnifloader ) add_component_dir (to_utf8 diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bulletnifloader.cpp similarity index 99% rename from components/nifbullet/bullet_nif_loader.cpp rename to components/nifbullet/bulletnifloader.cpp index e33754264..91fd6dbcf 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -21,7 +21,7 @@ http://www.gnu.org/licenses/ . */ -#include "bullet_nif_loader.hpp" +#include "bulletnifloader.hpp" #include #include diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bulletnifloader.hpp similarity index 96% rename from components/nifbullet/bullet_nif_loader.hpp rename to components/nifbullet/bulletnifloader.hpp index 0629b208d..0ff4b4ccd 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -21,8 +21,8 @@ */ -#ifndef _BULLET_NIF_LOADER_H_ -#define _BULLET_NIF_LOADER_H_ +#ifndef OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP +#define OPENMW_COMPONENTS_NIFBULLET_BULLETNIFLOADER_HPP #include #include diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogrenifloader.cpp similarity index 99% rename from components/nifogre/ogre_nif_loader.cpp rename to components/nifogre/ogrenifloader.cpp index d33243dd4..4eaedeaa8 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -21,7 +21,7 @@ */ -#include "ogre_nif_loader.hpp" +#include "ogrenifloader.hpp" #include diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogrenifloader.hpp similarity index 96% rename from components/nifogre/ogre_nif_loader.hpp rename to components/nifogre/ogrenifloader.hpp index eae37dd8a..b8b2e3c00 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -21,8 +21,8 @@ */ -#ifndef _OGRE_NIF_LOADER_H_ -#define _OGRE_NIF_LOADER_H_ +#ifndef OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP +#define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP #include #include diff --git a/components/nifoverrides/nifoverrides.hpp b/components/nifoverrides/nifoverrides.hpp index c9b711df6..ba2e4cc3c 100644 --- a/components/nifoverrides/nifoverrides.hpp +++ b/components/nifoverrides/nifoverrides.hpp @@ -1,5 +1,5 @@ -#ifndef COMPONENTS_NIFOVERRIDES_H -#define COMPONENTS_NIFOVERRIDES_H +#ifndef OPENMW_COMPONENTS_NIFOVERRIDES_NIFOVERRIDES_HPP +#define OPENMW_COMPONENTS_NIFOVERRIDES_NIFOVERRIDES_HPP #include diff --git a/libs/openengine/bullet/CMotionState.cpp b/libs/openengine/bullet/CMotionState.cpp index 6be615dfb..c20415884 100644 --- a/libs/openengine/bullet/CMotionState.cpp +++ b/libs/openengine/bullet/CMotionState.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace OEngine { namespace Physic diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index f993ce68e..119f6893a 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include "CMotionState.h" #include "OgreRoot.h" #include "btKinematicCharacterController.h" From 2b6bb9657bd46d2c2a5509a019647bcaa12dc7bb Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sat, 2 Mar 2013 23:49:31 +0100 Subject: [PATCH 848/916] Added Qt Designer .ui files --- apps/launcher/CMakeLists.txt | 10 +- apps/launcher/ui/graphicspage.ui | 134 +++++++++++++++++++++++ apps/launcher/ui/mainwindow.ui | 80 ++++++++++++++ apps/launcher/ui/playpage.ui | 180 +++++++++++++++++++++++++++++++ 4 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 apps/launcher/ui/graphicspage.ui create mode 100644 apps/launcher/ui/mainwindow.ui create mode 100644 apps/launcher/ui/playpage.ui diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index b2e6c7009..bc3969097 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -53,7 +53,13 @@ set(LAUNCHER_HEADER_MOC utils/textinputdialog.hpp ) -source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC}) +set(LAUNCHER_UI + ui/graphicspage.ui + ui/mainwindow.ui + ui/playpage.ui +) + +source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) find_package(Qt4 REQUIRED) set(QT_USE_QTGUI 1) @@ -66,6 +72,7 @@ endif(WIN32) QT4_ADD_RESOURCES(RCC_SRCS resources.qrc) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) +QT4_WRAP_UI(UI_HDRS ${LAUCHER_UI}) include(${QT_USE_FILE}) @@ -85,6 +92,7 @@ add_executable(omwlauncher ${LAUNCHER_HEADER} ${RCC_SRCS} ${MOC_SRCS} + ${UI_HDRS} ) target_link_libraries(omwlauncher diff --git a/apps/launcher/ui/graphicspage.ui b/apps/launcher/ui/graphicspage.ui new file mode 100644 index 000000000..670b4f9c6 --- /dev/null +++ b/apps/launcher/ui/graphicspage.ui @@ -0,0 +1,134 @@ + + + graphicsPage + + + + 0 + 0 + 400 + 300 + + + + + + + Render System + + + + + + Rendering Subsystem: + + + + + + + + + + + + + GroupBox + + + + + + Vertical Sync + + + + + + + Full Screen + + + + + + + Anti-aliasing: + + + + + + + Resolution: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + Custom: + + + + + + + Standard: + + + true + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 61 + + + + + + + + + diff --git a/apps/launcher/ui/mainwindow.ui b/apps/launcher/ui/mainwindow.ui new file mode 100644 index 000000000..4e1a7854d --- /dev/null +++ b/apps/launcher/ui/mainwindow.ui @@ -0,0 +1,80 @@ + + + MainWindow + + + + 0 + 0 + 575 + 575 + + + + + 575 + 575 + + + + OpenMW Launcher + + + + :/images/openmw.png:/images/openmw.png + + + + + + + + 400 + 80 + + + + + 16777215 + 80 + + + + #iconWidget { + background-image: url(":/images/openmw-header.png"); + background-color: white; + background-repeat: no-repeat; + background-attachment: scroll; + background-position: right; +} + + + + + + + + + + + + + + + + + + + + QDialogButtonBox::Close + + + + + + + + + + + diff --git a/apps/launcher/ui/playpage.ui b/apps/launcher/ui/playpage.ui new file mode 100644 index 000000000..86a763f64 --- /dev/null +++ b/apps/launcher/ui/playpage.ui @@ -0,0 +1,180 @@ + + + playPage + + + #playPage { + background-image: url(":/images/playpage-background.png"); + background-repeat: no-repeat; + background-position: top; +} + + + + + 30 + + + 100 + + + 30 + + + + + + 200 + 85 + + + + + 200 + 85 + + + + #playButton { + height: 50px; + margin-bottom: 30px; + + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(255, 255, 255, 200), + stop:0.1 rgba(255, 255, 255, 15), + stop:0.49 rgba(255, 255, 255, 75), + stop:0.5 rgba(0, 0, 0, 0), + stop:0.9 rgba(0, 0, 0, 55), + stop:1 rgba(0, 0, 0, 100)); + + font-size: 26pt; + font-family: "EB Garamond", "EB Garamond 08"; + color: black; + + border-right: 1px solid rgba(0, 0, 0, 155); + border-left: 1px solid rgba(0, 0, 0, 55); + border-top: 1px solid rgba(0, 0, 0, 55); + border-bottom: 1px solid rgba(0, 0, 0, 155); + + border-radius: 5px; +} + +#playButton:hover { + border-bottom: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-top: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-right: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-left: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-width: 2px; + border-style: solid; +} + +#playButton:pressed { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(0, 0, 0, 75), + stop:0.1 rgba(0, 0, 0, 15), + stop:0.2 rgba(255, 255, 255, 55) + stop:0.95 rgba(255, 255, 255, 55), + stop:1 rgba(255, 255, 255, 155)); + + border: 1px solid rgba(0, 0, 0, 55); +} + + + Play + + + + + + + #profileLabel { + font-size: 18pt; + font-family: "EB Garamond", "EB Garamond 08"; +} + + + + Current Profile: + + + + + + + #profilesComboBox { + padding: 1px 18px 1px 3px; + + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 white, stop:0.2 rgba(0, 0, 0, 25), stop:1 white); + border-width: 1px; + border-color: rgba(0, 0, 0, 125); + border-style: solid; + border-radius: 2px; +} + +/*QComboBox gets the "on" state when the popup is open */ +#profilesComboBox:!editable:on, #ProfilesComboBox::drop-down:editable:on { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(0, 0, 0, 75), + stop:0.1 rgba(0, 0, 0, 15), + stop:0.2 rgba(255, 255, 255, 55)); + + border: 1px solid rgba(0, 0, 0, 55); +} + +#profilesComboBox { /* shift the text when the popup opens */ + padding-top: 3px; + padding-left: 4px; + + font-size: 12pt; + font-family: "EB Garamond", "EB Garamond 08"; +} + +#profilesComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: top right; + + border-width: 1px; + border-left-width: 1px; + border-left-color: darkgray; + border-left-style: solid; /* just a single line */ + border-top-right-radius: 3px; /* same radius as the QComboBox */ + border-bottom-right-radius: 3px; +} + +#profilesComboBox::down-arrow { + image: url(":/images/down.png"); +} + +#profilesComboBox::down-arrow:on { /* shift the arrow when popup is open */ + top: 1px; + left: 1px; +} + +#profilesComboBox QAbstractItemView { + border: 2px solid lightgray; + border-radius: 5px; +} + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + From f2193bb1bacde7fe5c37475cab839c3f2e08374f Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 3 Mar 2013 00:48:09 +0100 Subject: [PATCH 849/916] Made the mainwindow use a .ui file and removed the stylesheet --- CMakeLists.txt | 6 -- apps/launcher/CMakeLists.txt | 22 ++----- apps/launcher/maindialog.cpp | 92 +++++++------------------- apps/launcher/maindialog.hpp | 8 ++- files/launcher.qss | 123 ----------------------------------- 5 files changed, 35 insertions(+), 216 deletions(-) delete mode 100644 files/launcher.qss diff --git a/CMakeLists.txt b/CMakeLists.txt index e583f23d4..6498e723c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -379,7 +379,6 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/OFL.txt" "${OpenMW_SOURCE_DIR}/DejaVu Font License.txt" "${OpenMW_SOURCE_DIR}/Daedric Font License.txt" - "${OpenMW_BINARY_DIR}/launcher.qss" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" "${OpenMW_BINARY_DIR}/Release/omwlauncher.exe" @@ -566,8 +565,6 @@ if (APPLE) install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) @@ -681,7 +678,4 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) # Install resources INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) - IF(BUILD_LAUNCHER) - INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) - ENDIF(BUILD_LAUNCHER) endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index bc3969097..206e94794 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -36,6 +36,7 @@ set(LAUNCHER_HEADER utils/comboboxlineedit.hpp utils/profilescombobox.hpp utils/textinputdialog.hpp + ) # Headers that must be pre-processed @@ -54,9 +55,9 @@ set(LAUNCHER_HEADER_MOC ) set(LAUNCHER_UI - ui/graphicspage.ui - ui/mainwindow.ui - ui/playpage.ui + ./ui/graphicspage.ui + ./ui/mainwindow.ui + ./ui/playpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) @@ -72,9 +73,10 @@ endif(WIN32) QT4_ADD_RESOURCES(RCC_SRCS resources.qrc) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) -QT4_WRAP_UI(UI_HDRS ${LAUCHER_UI}) +QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) include(${QT_USE_FILE}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) # Main executable IF(OGRE_STATIC) @@ -107,18 +109,6 @@ if(DPKG_PROGRAM) INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher) endif() -if (APPLE) - configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss - "${APP_BUNDLE_DIR}/../launcher.qss") -else() - configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss - "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources/launcher.qss") - - # Fallback in case getGlobalDataPath does not point to resources - configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss - "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss") -endif() - if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(omwlauncher gcov) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index e69f134d2..f438e64c9 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -12,46 +12,6 @@ MainDialog::MainDialog() : mGameSettings(mCfgMgr) { - QWidget *centralWidget = new QWidget(this); - setCentralWidget(centralWidget); - - mIconWidget = new QListWidget(centralWidget); - mIconWidget->setObjectName("IconWidget"); - mIconWidget->setViewMode(QListView::IconMode); - mIconWidget->setWrapping(false); - mIconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure - mIconWidget->setIconSize(QSize(48, 48)); - mIconWidget->setMovement(QListView::Static); - - mIconWidget->setMinimumWidth(400); - mIconWidget->setFixedHeight(80); - mIconWidget->setSpacing(4); - mIconWidget->setCurrentRow(0); - mIconWidget->setFlow(QListView::LeftToRight); - - QGroupBox *groupBox = new QGroupBox(centralWidget); - QVBoxLayout *groupLayout = new QVBoxLayout(groupBox); - - mPagesWidget = new QStackedWidget(groupBox); - groupLayout->addWidget(mPagesWidget); - - QPushButton *playButton = new QPushButton(tr("Play")); - - QDialogButtonBox *buttonBox = new QDialogButtonBox(centralWidget); - buttonBox->setStandardButtons(QDialogButtonBox::Close); - buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole); - - QVBoxLayout *dialogLayout = new QVBoxLayout(centralWidget); - dialogLayout->addWidget(mIconWidget); - dialogLayout->addWidget(groupBox); - dialogLayout->addWidget(buttonBox); - - setWindowTitle(tr("OpenMW Launcher")); - setWindowIcon(QIcon(":/images/openmw.png")); - // Remove what's this? button - setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); - setMinimumSize(QSize(575, 575)); - // Install the stylesheet font QFile file; QFontDatabase fontDatabase; @@ -71,31 +31,27 @@ MainDialog::MainDialog() fontDatabase.addApplicationFont(font); } - // Load the stylesheet - QString config = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/launcher.qss"); - file.setFileName(config); + setupUi(this); - if (!file.exists()) - file.setFileName(QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("launcher.qss")); + iconWidget->setViewMode(QListView::IconMode); + iconWidget->setWrapping(false); + iconWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Just to be sure + iconWidget->setIconSize(QSize(48, 48)); + iconWidget->setMovement(QListView::Static); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening Launcher stylesheet")); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - } else { - QString styleSheet = QLatin1String(file.readAll()); - qApp->setStyleSheet(styleSheet); - file.close(); - } + iconWidget->setSpacing(4); + iconWidget->setCurrentRow(0); + iconWidget->setFlow(QListView::LeftToRight); + + QPushButton *playButton = new QPushButton(tr("Play")); + buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole); connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); + // Remove what's this? button + setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); + createIcons(); } @@ -107,25 +63,25 @@ void MainDialog::createIcons() // We create a fallback icon because the default fallback doesn't work QIcon graphicsIcon = QIcon(":/icons/tango/video-display.png"); - QListWidgetItem *playButton = new QListWidgetItem(mIconWidget); + QListWidgetItem *playButton = new QListWidgetItem(iconWidget); playButton->setIcon(QIcon(":/images/openmw.png")); playButton->setText(tr("Play")); playButton->setTextAlignment(Qt::AlignCenter); playButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - QListWidgetItem *graphicsButton = new QListWidgetItem(mIconWidget); + QListWidgetItem *graphicsButton = new QListWidgetItem(iconWidget); graphicsButton->setIcon(QIcon::fromTheme("video-display", graphicsIcon)); graphicsButton->setText(tr("Graphics")); graphicsButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom | Qt::AlignAbsolute); graphicsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - QListWidgetItem *dataFilesButton = new QListWidgetItem(mIconWidget); + QListWidgetItem *dataFilesButton = new QListWidgetItem(iconWidget); dataFilesButton->setIcon(QIcon(":/images/openmw-plugin.png")); dataFilesButton->setText(tr("Data Files")); dataFilesButton->setTextAlignment(Qt::AlignHCenter | Qt::AlignBottom); dataFilesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - connect(mIconWidget, + connect(iconWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*))); @@ -142,12 +98,12 @@ void MainDialog::createPages() mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget - mPagesWidget->addWidget(mPlayPage); - mPagesWidget->addWidget(mGraphicsPage); - mPagesWidget->addWidget(mDataFilesPage); + pagesWidget->addWidget(mPlayPage); + pagesWidget->addWidget(mGraphicsPage); + pagesWidget->addWidget(mDataFilesPage); // Select the first page - mIconWidget->setCurrentItem(mIconWidget->item(0), QItemSelectionModel::Select); + iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select); connect(mPlayPage->mPlayButton, SIGNAL(clicked()), this, SLOT(play())); @@ -326,7 +282,7 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) if (!current) current = previous; - mPagesWidget->setCurrentIndex(mIconWidget->row(current)); + pagesWidget->setCurrentIndex(iconWidget->row(current)); } bool MainDialog::setupLauncherSettings() diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index f221bd5e6..780cd8beb 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -9,6 +9,8 @@ #include "settings/graphicssettings.hpp" #include "settings/launchersettings.hpp" +#include "ui_mainwindow.h" + class QListWidget; class QListWidgetItem; class QStackedWidget; @@ -20,7 +22,7 @@ class PlayPage; class GraphicsPage; class DataFilesPage; -class MainDialog : public QMainWindow +class MainDialog : public QMainWindow, private Ui::MainWindow { Q_OBJECT @@ -56,8 +58,8 @@ private: void closeEvent(QCloseEvent *event); - QListWidget *mIconWidget; - QStackedWidget *mPagesWidget; +// QListWidget *mIconWidget; +// QStackedWidget *mPagesWidget; PlayPage *mPlayPage; GraphicsPage *mGraphicsPage; diff --git a/files/launcher.qss b/files/launcher.qss deleted file mode 100644 index 1eb056d4d..000000000 --- a/files/launcher.qss +++ /dev/null @@ -1,123 +0,0 @@ -#PlayGroup { - background-image: url(":/images/playpage-background.png"); - background-repeat: no-repeat; - background-position: top; - padding-left: 30px; - padding-right: 30px; -} - -#MastersWidget { - selection-background-color: palette(highlight); -} - -#PlayButton { - height: 50px; - margin-bottom: 30px; - - background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(255, 255, 255, 200), - stop:0.1 rgba(255, 255, 255, 15), - stop:0.49 rgba(255, 255, 255, 75), - stop:0.5 rgba(0, 0, 0, 0), - stop:0.9 rgba(0, 0, 0, 55), - stop:1 rgba(0, 0, 0, 100)); - - font-size: 26pt; - font-family: "EB Garamond", "EB Garamond 08"; - color: black; - - border-right: 1px solid rgba(0, 0, 0, 155); - border-left: 1px solid rgba(0, 0, 0, 55); - border-top: 1px solid rgba(0, 0, 0, 55); - border-bottom: 1px solid rgba(0, 0, 0, 155); - - border-radius: 5px; -} - -#PlayButton:hover { - border-bottom: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-top: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-right: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-left: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-width: 2px; - border-style: solid; -} - -#PlayButton:pressed { - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(0, 0, 0, 75), - stop:0.1 rgba(0, 0, 0, 15), - stop:0.2 rgba(255, 255, 255, 55) - stop:0.95 rgba(255, 255, 255, 55), - stop:1 rgba(255, 255, 255, 155)); - - border: 1px solid rgba(0, 0, 0, 55); -} - -#ProfileLabel { - font-size: 18pt; - font-family: "EB Garamond", "EB Garamond 08"; -} - -#ProfilesComboBox { - padding: 1px 18px 1px 3px; - - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 white, stop:0.2 rgba(0, 0, 0, 25), stop:1 white); - border-width: 1px; - border-color: rgba(0, 0, 0, 125); - border-style: solid; - border-radius: 2px; -} - -/*QComboBox gets the "on" state when the popup is open */ -#ProfilesComboBox:!editable:on, #ProfilesComboBox::drop-down:editable:on { - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(0, 0, 0, 75), - stop:0.1 rgba(0, 0, 0, 15), - stop:0.2 rgba(255, 255, 255, 55)); - - border: 1px solid rgba(0, 0, 0, 55); -} - - -#ProfilesComboBox { /* shift the text when the popup opens */ - padding-top: 3px; - padding-left: 4px; - - font-size: 12pt; - font-family: "EB Garamond", "EB Garamond 08"; -} - -#ProfilesComboBox::drop-down { - subcontrol-origin: padding; - subcontrol-position: top right; - - border-width: 1px; - border-left-width: 1px; - border-left-color: darkgray; - border-left-style: solid; /* just a single line */ - border-top-right-radius: 3px; /* same radius as the QComboBox */ - border-bottom-right-radius: 3px; -} - -#ProfilesComboBox::down-arrow { - image: url(":/images/down.png"); -} - -#ProfilesComboBox::down-arrow:on { /* shift the arrow when popup is open */ - top: 1px; - left: 1px; -} - -#ProfilesComboBox QAbstractItemView { - border: 2px solid lightgray; - border-radius: 5px; -} - -#IconWidget { - background-image: url(":/images/openmw-header.png"); - background-color: white; - background-repeat: no-repeat; - background-attachment: scroll; - background-position: right; -} From 03785f3ecda06bad6a8c85af8aa7490da28c9f07 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 16:28:32 -0800 Subject: [PATCH 850/916] Handle NiVertexColorProperty --- components/nifogre/ogre_nif_loader.cpp | 61 +++++++++++++++++++------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1d9c4d748..1d0d31961 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -552,7 +552,8 @@ public: static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop) + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -567,6 +568,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String float alpha = 1.0f; int alphaFlags = 0; int alphaTest = 0; + int vertMode = 2; + //int lightMode = 1; Ogre::String texName; bool vertexColour = (shape->data->colors.size() != 0); @@ -617,6 +620,14 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String alphaTest = alphaprop->data.threshold; } + // Vertex color handling + if(vertprop) + { + vertMode = vertprop->data.vertmode; + // FIXME: Handle lightmode? + //lightMode = vertprop->data.lightmode; + } + // Material if(matprop) { @@ -649,6 +660,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); + boost::hash_combine(h, vertMode); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -662,19 +674,31 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // No existing material like this. Create a new one. sh::MaterialInstance* instance = sh::Factory::getInstance ().createMaterialInstance (matname, "openmw_objects_base"); - instance->setProperty ("ambient", sh::makeProperty ( - new sh::Vector3(ambient.x, ambient.y, ambient.z))); + if(vertMode == 0 || !vertexColour) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, alpha))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, alpha))); + } + else if(vertMode == 1) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, alpha))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); + } + else if(vertMode == 2) + { + instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, alpha))); + } + else + std::cerr<< "Unhandled vertex mode: "<setProperty ("diffuse", sh::makeProperty ( - new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - - instance->setProperty ("specular", sh::makeProperty ( + instance->setProperty("specular", sh::makeProperty( new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); - instance->setProperty ("emissive", sh::makeProperty ( - new sh::Vector3(emissive.x, emissive.y, emissive.z))); - - instance->setProperty ("diffuseMap", sh::makeProperty(texName)); + instance->setProperty("diffuseMap", sh::makeProperty(texName)); if (vertexColour) instance->setProperty ("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); @@ -744,7 +768,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape, const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop) + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -943,7 +968,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, - texprop, matprop, alphaprop); + texprop, matprop, alphaprop, + vertprop); if(matname.length() > 0) sub->setMaterialName(matname); } @@ -951,7 +977,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, const Nif::NiTexturingProperty *texprop=NULL, const Nif::NiMaterialProperty *matprop=NULL, - const Nif::NiAlphaProperty *alphaprop=NULL) + const Nif::NiAlphaProperty *alphaprop=NULL, + const Nif::NiVertexColorProperty *vertprop=NULL) { // Scan the property list for material information const Nif::PropertyList &proplist = node->props; @@ -968,13 +995,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader matprop = static_cast(pr); else if(pr->recType == Nif::RC_NiAlphaProperty) alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop); + handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop); return true; } @@ -986,7 +1015,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop)) + if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop)) return true; } } From 0a6e3701abf08bb5804f151ab8bd4f87e31a7e90 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Sun, 3 Mar 2013 01:49:41 +0100 Subject: [PATCH 851/916] Made the Play page use a .ui file too --- apps/launcher/maindialog.cpp | 15 +- apps/launcher/maindialog.hpp | 9 -- apps/launcher/playpage.cpp | 58 ++++---- apps/launcher/playpage.hpp | 22 ++- apps/launcher/ui/graphicspage.ui | 4 +- apps/launcher/ui/playpage.ui | 228 ++++++++++++++++--------------- 6 files changed, 170 insertions(+), 166 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index f438e64c9..5621b75c0 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -94,8 +94,8 @@ void MainDialog::createPages() mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage - mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model()); - mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); + mPlayPage->setProfilesComboBoxModel(mDataFilesPage->mProfilesComboBox->model()); + mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget pagesWidget->addWidget(mPlayPage); @@ -105,15 +105,10 @@ void MainDialog::createPages() // Select the first page iconWidget->setCurrentItem(iconWidget->item(0), QItemSelectionModel::Select); - connect(mPlayPage->mPlayButton, SIGNAL(clicked()), this, SLOT(play())); + connect(mPlayPage, SIGNAL(playButtonClicked()), this, SLOT(play())); - connect(mPlayPage->mProfilesComboBox, - SIGNAL(currentIndexChanged(int)), - mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); - - connect(mDataFilesPage->mProfilesComboBox, - SIGNAL(currentIndexChanged(int)), - mPlayPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); + connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); + connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); } diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 780cd8beb..643206ab6 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -28,12 +28,6 @@ class MainDialog : public QMainWindow, private Ui::MainWindow public: MainDialog(); - - -// GameSettings &gameSettings, -// GraphicsSettings &GraphicsSettings, -// LauncherSettings &launcherSettings); - bool setup(); bool showFirstRunDialog(); @@ -58,9 +52,6 @@ private: void closeEvent(QCloseEvent *event); -// QListWidget *mIconWidget; -// QStackedWidget *mPagesWidget; - PlayPage *mPlayPage; GraphicsPage *mGraphicsPage; DataFilesPage *mDataFilesPage; diff --git a/apps/launcher/playpage.cpp b/apps/launcher/playpage.cpp index b082e2e2c..27b7846dd 100644 --- a/apps/launcher/playpage.cpp +++ b/apps/launcher/playpage.cpp @@ -4,45 +4,37 @@ PlayPage::PlayPage(QWidget *parent) : QWidget(parent) { - QWidget *playWidget = new QWidget(this); - playWidget->setObjectName("PlayGroup"); - playWidget->setFixedSize(QSize(425, 375)); - - mPlayButton = new QPushButton(tr("Play"), playWidget); - mPlayButton->setObjectName("PlayButton"); - mPlayButton->setMinimumSize(QSize(200, 50)); - - QLabel *profileLabel = new QLabel(tr("Current Profile:"), playWidget); - profileLabel->setObjectName("ProfileLabel"); + setupUi(this); // Hacks to get the stylesheet look properly on different platforms QPlastiqueStyle *style = new QPlastiqueStyle; QFont font = QApplication::font(); font.setPointSize(12); // Fixes problem with overlapping items - mProfilesComboBox = new QComboBox(playWidget); - mProfilesComboBox->setObjectName("ProfilesComboBox"); - mProfilesComboBox->setStyle(style); - mProfilesComboBox->setFont(font); + profilesComboBox->setStyle(style); + profilesComboBox->setFont(font); - QGridLayout *playLayout = new QGridLayout(playWidget); - - QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - QSpacerItem *hSpacer2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - QSpacerItem *vSpacer1 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - QSpacerItem *vSpacer2 = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); - - playLayout->addWidget(mPlayButton, 1, 1, 1, 1); - playLayout->addWidget(profileLabel, 2, 1, 1, 1); - playLayout->addWidget(mProfilesComboBox, 3, 1, 1, 1); - playLayout->addItem(hSpacer1, 2, 0, 1, 1); - playLayout->addItem(hSpacer2, 2, 2, 1, 1); - playLayout->addItem(vSpacer1, 0, 1, 1, 1); - playLayout->addItem(vSpacer2, 4, 1, 1, 1); - - QHBoxLayout *pageLayout = new QHBoxLayout(this); - - pageLayout->addWidget(playWidget); + connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int))); + connect(playButton, SIGNAL(clicked()), this, SLOT(slotPlayClicked())); } + +void PlayPage::setProfilesComboBoxModel(QAbstractItemModel *model) +{ + profilesComboBox->setModel(model); +} + +void PlayPage::setProfilesComboBoxIndex(int index) +{ + profilesComboBox->setCurrentIndex(index); +} + +void PlayPage::slotCurrentIndexChanged(int index) +{ + emit profileChanged(index); +} + +void PlayPage::slotPlayClicked() +{ + emit playButtonClicked(); +} diff --git a/apps/launcher/playpage.hpp b/apps/launcher/playpage.hpp index efec6f2b3..4306396bd 100644 --- a/apps/launcher/playpage.hpp +++ b/apps/launcher/playpage.hpp @@ -3,19 +3,33 @@ #include +#include "ui_playpage.h" + class QComboBox; class QPushButton; +class QAbstractItemModel; -class PlayPage : public QWidget +class PlayPage : public QWidget, private Ui::PlayPage { Q_OBJECT public: PlayPage(QWidget *parent = 0); + void setProfilesComboBoxModel(QAbstractItemModel *model); + +signals: + void profileChanged(int index); + void playButtonClicked(); + +public slots: + void setProfilesComboBoxIndex(int index); + +private slots: + void slotCurrentIndexChanged(int index); + void slotPlayClicked(); + - QComboBox *mProfilesComboBox; - QPushButton *mPlayButton; }; -#endif \ No newline at end of file +#endif diff --git a/apps/launcher/ui/graphicspage.ui b/apps/launcher/ui/graphicspage.ui index 670b4f9c6..e04cd5855 100644 --- a/apps/launcher/ui/graphicspage.ui +++ b/apps/launcher/ui/graphicspage.ui @@ -1,7 +1,7 @@ - graphicsPage - + GraphicsPage + 0 diff --git a/apps/launcher/ui/playpage.ui b/apps/launcher/ui/playpage.ui index 86a763f64..ccd17f519 100644 --- a/apps/launcher/ui/playpage.ui +++ b/apps/launcher/ui/playpage.ui @@ -1,107 +1,38 @@ - playPage - - - #playPage { + PlayPage + + + + + + #Scroll { background-image: url(":/images/playpage-background.png"); background-repeat: no-repeat; background-position: top; } - - - - 30 - - - 100 - - - 30 - - - - - - 200 - 85 - - - - 200 - 85 - + + QFrame::StyledPanel - - #playButton { - height: 50px; - margin-bottom: 30px; - - background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(255, 255, 255, 200), - stop:0.1 rgba(255, 255, 255, 15), - stop:0.49 rgba(255, 255, 255, 75), - stop:0.5 rgba(0, 0, 0, 0), - stop:0.9 rgba(0, 0, 0, 55), - stop:1 rgba(0, 0, 0, 100)); - - font-size: 26pt; - font-family: "EB Garamond", "EB Garamond 08"; - color: black; - - border-right: 1px solid rgba(0, 0, 0, 155); - border-left: 1px solid rgba(0, 0, 0, 55); - border-top: 1px solid rgba(0, 0, 0, 55); - border-bottom: 1px solid rgba(0, 0, 0, 155); - - border-radius: 5px; -} - -#playButton:hover { - border-bottom: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-top: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-right: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-left: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); - border-width: 2px; - border-style: solid; -} - -#playButton:pressed { - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, - stop:0 rgba(0, 0, 0, 75), - stop:0.1 rgba(0, 0, 0, 15), - stop:0.2 rgba(255, 255, 255, 55) - stop:0.95 rgba(255, 255, 255, 55), - stop:1 rgba(255, 255, 255, 155)); - - border: 1px solid rgba(0, 0, 0, 55); -} + + QFrame::Plain - - Play - - - - - - - #profileLabel { - font-size: 18pt; - font-family: "EB Garamond", "EB Garamond 08"; -} - - - - Current Profile: - - - - - - - #profilesComboBox { + + + 30 + + + 100 + + + 30 + + + + + #profilesComboBox { padding: 1px 18px 1px 3px; background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 white, stop:0.2 rgba(0, 0, 0, 25), stop:1 white); @@ -155,22 +86,103 @@ border-radius: 5px; } - + + + + + + + #profileLabel { + font-size: 18pt; + font-family: "EB Garamond", "EB Garamond 08"; +} + + + + Current Profile: + + + + + + + + 200 + 85 + + + + + 200 + 85 + + + + #playButton { + height: 50px; + margin-bottom: 30px; + + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(255, 255, 255, 200), + stop:0.1 rgba(255, 255, 255, 15), + stop:0.49 rgba(255, 255, 255, 75), + stop:0.5 rgba(0, 0, 0, 0), + stop:0.9 rgba(0, 0, 0, 55), + stop:1 rgba(0, 0, 0, 100)); + + font-size: 26pt; + font-family: "EB Garamond", "EB Garamond 08"; + color: black; + + border-right: 1px solid rgba(0, 0, 0, 155); + border-left: 1px solid rgba(0, 0, 0, 55); + border-top: 1px solid rgba(0, 0, 0, 55); + border-bottom: 1px solid rgba(0, 0, 0, 155); + + border-radius: 5px; +} + +#playButton:hover { + border-bottom: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-top: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-right: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-left: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(164, 192, 228, 255), stop:1 rgba(255, 255, 255, 0)); + border-width: 2px; + border-style: solid; +} + +#playButton:pressed { + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, + stop:0 rgba(0, 0, 0, 75), + stop:0.1 rgba(0, 0, 0, 15), + stop:0.2 rgba(255, 255, 255, 55) + stop:0.95 rgba(255, 255, 255, 55), + stop:1 rgba(255, 255, 255, 155)); + + border: 1px solid rgba(0, 0, 0, 55); +} + + + Play + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + - - - - Qt::Vertical - - - - 20 - 40 - - - - From 8c0326a49c94583fc50eff481408c59654fdee6f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 18:30:28 -0800 Subject: [PATCH 852/916] Handle NiZBufferProperty --- components/nifogre/ogre_nif_loader.cpp | 33 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1d0d31961..1ea911a77 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -553,7 +553,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop) + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -570,6 +571,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int alphaTest = 0; int vertMode = 2; //int lightMode = 1; + int depthFlags = 3; Ogre::String texName; bool vertexColour = (shape->data->colors.size() != 0); @@ -628,6 +630,12 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String //lightMode = vertprop->data.lightmode; } + if(zprop) + { + depthFlags = zprop->flags; + // Depth function??? + } + // Material if(matprop) { @@ -731,8 +739,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(((alphaFlags>>13)&1) ? - "off" : "on"))); + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::BooleanValue(!((alphaFlags>>13)&1)))); + + instance->setProperty("depth_check", sh::makeProperty(new sh::BooleanValue(depthFlags&1))); + instance->setProperty("depth_write", sh::makeProperty(new sh::BooleanValue((depthFlags>>1)&1))); + // depth_func??? sh::Factory::getInstance()._ensureMaterial(matname, "Default"); return matname; @@ -769,7 +780,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop) + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -969,7 +981,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, texprop, matprop, alphaprop, - vertprop); + vertprop, zprop); if(matname.length() > 0) sub->setMaterialName(matname); } @@ -978,7 +990,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiTexturingProperty *texprop=NULL, const Nif::NiMaterialProperty *matprop=NULL, const Nif::NiAlphaProperty *alphaprop=NULL, - const Nif::NiVertexColorProperty *vertprop=NULL) + const Nif::NiVertexColorProperty *vertprop=NULL, + const Nif::NiZBufferProperty *zprop=NULL) { // Scan the property list for material information const Nif::PropertyList &proplist = node->props; @@ -997,25 +1010,27 @@ class NIFMeshLoader : Ogre::ManualResourceLoader alphaprop = static_cast(pr); else if(pr->recType == Nif::RC_NiVertexColorProperty) vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop); + handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop); return true; } const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { - Nif::NodeList const &children = ninode->children; + const Nif::NodeList &children = ninode->children; for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop)) + if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop)) return true; } } From 8e35159ad4e5372d6bd0dcaad9542f33b8f3b753 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 19:06:28 -0800 Subject: [PATCH 853/916] Handle NiSpecularProperty --- components/nifogre/ogre_nif_loader.cpp | 33 +++++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 1ea911a77..773a6b18d 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -554,7 +554,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop) + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -572,6 +573,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int vertMode = 2; //int lightMode = 1; int depthFlags = 3; + int specFlags = 1; Ogre::String texName; bool vertexColour = (shape->data->colors.size() != 0); @@ -636,6 +638,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String // Depth function??? } + if(specprop) + { + specFlags = specprop->flags; + } + // Material if(matprop) { @@ -669,6 +676,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); boost::hash_combine(h, vertMode); + boost::hash_combine(h, specFlags); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -703,13 +711,16 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String else std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); + if(specFlags) + { + instance->setProperty("specular", sh::makeProperty( + new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); + } instance->setProperty("diffuseMap", sh::makeProperty(texName)); if (vertexColour) - instance->setProperty ("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Add transparency if NiAlphaProperty was present NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); @@ -781,7 +792,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop) + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -981,7 +993,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, texprop, matprop, alphaprop, - vertprop, zprop); + vertprop, zprop, specprop); if(matname.length() > 0) sub->setMaterialName(matname); } @@ -991,7 +1003,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiMaterialProperty *matprop=NULL, const Nif::NiAlphaProperty *alphaprop=NULL, const Nif::NiVertexColorProperty *vertprop=NULL, - const Nif::NiZBufferProperty *zprop=NULL) + const Nif::NiZBufferProperty *zprop=NULL, + const Nif::NiSpecularProperty *specprop=NULL) { // Scan the property list for material information const Nif::PropertyList &proplist = node->props; @@ -1012,13 +1025,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader vertprop = static_cast(pr); else if(pr->recType == Nif::RC_NiZBufferProperty) zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop); + handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop, specprop); return true; } @@ -1030,7 +1045,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop)) + if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop, specprop)) return true; } } From 7930aa82b2d90e96bc11dc9e20b99650561ebdba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 19:09:15 -0800 Subject: [PATCH 854/916] Add missing depthFlags to the hash --- components/nifogre/ogre_nif_loader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 773a6b18d..9537f550b 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -676,6 +676,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); boost::hash_combine(h, vertMode); + boost::hash_combine(h, depthFlags); boost::hash_combine(h, specFlags); std::map::iterator itr = MaterialMap.find(h); From 21e2c287ebf60130db3669666d0557d8b34c4f7b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 2 Mar 2013 19:30:23 -0800 Subject: [PATCH 855/916] Fix/workaround specular issues The glossiness should not be multiplied by 255, however the values set in many of Bloodmoon's meshes would look horrible otherwise. Now we can let the NiSpecularProperty specify when to enable specular (which is supposed to default to on, but due to the aforementioned meshes, we default to off). --- components/nifogre/ogre_nif_loader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9537f550b..9652fd605 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -573,7 +573,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int vertMode = 2; //int lightMode = 1; int depthFlags = 3; - int specFlags = 1; + // Default should be 1, but Bloodmoon's models are broken + int specFlags = 0; Ogre::String texName; bool vertexColour = (shape->data->colors.size() != 0); @@ -715,7 +716,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String if(specFlags) { instance->setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness*255.0f))); + new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } instance->setProperty("diffuseMap", sh::makeProperty(texName)); From cf87708c1fc4a83aac6c668f3125020373371a5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 12:01:19 +0100 Subject: [PATCH 856/916] Magic effect icons for spells --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/hud.cpp | 23 ++- apps/openmw/mwgui/hud.hpp | 10 +- apps/openmw/mwgui/spellicons.cpp | 246 +++++++++++++++++++++++ apps/openmw/mwgui/spellicons.hpp | 47 +++++ apps/openmw/mwgui/spellwindow.cpp | 10 + apps/openmw/mwgui/spellwindow.hpp | 5 + apps/openmw/mwgui/tooltips.cpp | 12 +- apps/openmw/mwgui/tooltips.hpp | 4 + apps/openmw/mwgui/widgets.cpp | 12 +- apps/openmw/mwgui/windowmanagerimp.cpp | 3 + apps/openmw/mwgui/windowmanagerimp.hpp | 1 + apps/openmw/mwmechanics/activespells.cpp | 5 + apps/openmw/mwmechanics/activespells.hpp | 2 + files/mygui/openmw_hud.layout | 5 +- files/mygui/openmw_hud_box.skin.xml | 4 + files/mygui/openmw_spell_window.layout | 4 +- 17 files changed, 360 insertions(+), 35 deletions(-) create mode 100644 apps/openmw/mwgui/spellicons.cpp create mode 100644 apps/openmw/mwgui/spellicons.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 7cfeb84c5..e09dfb108 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -30,7 +30,7 @@ add_openmw_dir (mwgui formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog - enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor + enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a2c3a318b..2eb96249c 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -19,6 +19,7 @@ #include "inventorywindow.hpp" #include "container.hpp" #include "console.hpp" +#include "spellicons.hpp" using namespace MWGui; @@ -32,7 +33,6 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) , mWeapStatus(NULL) , mSpellStatus(NULL) , mEffectBox(NULL) - , mEffect1(NULL) , mMinimap(NULL) , mCompass(NULL) , mCrosshair(NULL) @@ -86,9 +86,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); getWidget(mEffectBox, "EffectBox"); - getWidget(mEffect1, "Effect1"); mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); - mEffectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); getWidget(mMinimapBox, "MiniMapBox"); mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); @@ -107,13 +105,18 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(mTriangleCounter, "TriangleCounter"); getWidget(mBatchCounter, "BatchCounter"); - setEffect("icons\\s\\tx_s_chameleon.dds"); - LocalMapBase::init(mMinimap, mCompass, this); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); + + mSpellIcons = new SpellIcons(); +} + +HUD::~HUD() +{ + delete mSpellIcons; } void HUD::setFpsLevel(int level) @@ -156,11 +159,6 @@ void HUD::setBatchCount(unsigned int count) mBatchCounter->setCaption(boost::lexical_cast(count)); } -void HUD::setEffect(const char *img) -{ - mEffect1->setImageTexture(img); -} - void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { static const char *ids[] = @@ -542,3 +540,8 @@ void HUD::updatePositions() mMapVisible = mMinimapBox->getVisible (); mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); } + +void HUD::update() +{ + mSpellIcons->updateWidgets(mEffectBox, true); +} diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 013ad59f0..39d6eadca 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -8,12 +8,13 @@ namespace MWGui { class DragAndDrop; + class SpellIcons; class HUD : public OEngine::GUI::Layout, public LocalMapBase { public: HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); - void setEffect(const char *img); + virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); void setTriangleCount(unsigned int count); @@ -43,6 +44,10 @@ namespace MWGui bool getWorldMouseOver() { return mWorldMouseOver; } + MyGUI::Widget* getEffectBox() { return mEffectBox; } + + void update(); + private: MyGUI::ProgressPtr mHealth, mMagicka, mStamina; MyGUI::Widget* mHealthFrame; @@ -51,7 +56,6 @@ namespace MWGui MyGUI::ProgressPtr mWeapStatus, mSpellStatus; MyGUI::Widget *mEffectBox, *mMinimapBox; MyGUI::Button* mMinimapButton; - MyGUI::ImageBox* mEffect1; MyGUI::ScrollView* mMinimap; MyGUI::ImageBox* mCompass; MyGUI::ImageBox* mCrosshair; @@ -85,6 +89,8 @@ namespace MWGui bool mWorldMouseOver; + SpellIcons* mSpellIcons; + void onWorldClicked(MyGUI::Widget* _sender); void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp new file mode 100644 index 000000000..19b2a87ec --- /dev/null +++ b/apps/openmw/mwgui/spellicons.cpp @@ -0,0 +1,246 @@ +#include "spellicons.hpp" + +#include +#include +#include + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/activespells.hpp" +#include "../mwmechanics/creaturestats.hpp" + +#include "tooltips.hpp" + + +namespace MWGui +{ + + void SpellIcons::updateWidgets(MyGUI::Widget *parent, bool adjustSize) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + + std::map > effects; + + // add permanent spells + const MWMechanics::Spells& spells = stats.getSpells(); + for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(it->first); + + // these are the spell types that are permanently in effect + if (!(spell->mData.mType == ESM::Spell::ST_Ability) + && !(spell->mData.mType == ESM::Spell::ST_Disease) + && !(spell->mData.mType == ESM::Spell::ST_Curse) + && !(spell->mData.mType == ESM::Spell::ST_Blight)) + continue; + ESM::EffectList list = spell->mEffects; + for (std::vector::const_iterator effectIt = list.mList.begin(); + effectIt != list.mList.end(); ++effectIt) + { + const ESM::MagicEffect* magicEffect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(effectIt->mEffectID); + MagicEffectInfo effectInfo; + effectInfo.mSource = getSpellDisplayName (it->first); + effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID); + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + effectInfo.mKey.mArg = effectIt->mSkill; + else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + effectInfo.mKey.mArg = effectIt->mAttribute; + // just using the min magnitude here, permanent spells with a random magnitude just wouldn't make any sense + effectInfo.mMagnitude = effectIt->mMagnMin; + effectInfo.mPermanent = true; + + effects[effectIt->mEffectID].push_back (effectInfo); + } + } + + // add lasting effect spells/potions etc + const MWMechanics::ActiveSpells::TContainer& activeSpells = stats.getActiveSpells().getActiveSpells(); + for (MWMechanics::ActiveSpells::TContainer::const_iterator it = activeSpells.begin(); + it != activeSpells.end(); ++it) + { + ESM::EffectList list = getSpellEffectList(it->first); + + float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + + for (std::vector::const_iterator effectIt = list.mList.begin(); + effectIt != list.mList.end(); ++effectIt) + { + const ESM::MagicEffect* magicEffect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(effectIt->mEffectID); + + MagicEffectInfo effectInfo; + effectInfo.mSource = getSpellDisplayName (it->first); + effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID); + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + effectInfo.mKey.mArg = effectIt->mSkill; + else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + effectInfo.mKey.mArg = effectIt->mAttribute; + effectInfo.mMagnitude = effectIt->mMagnMin + (effectIt->mMagnMax-effectIt->mMagnMin) * it->second.second; + effectInfo.mRemainingTime = effectIt->mDuration + + (it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + + effects[effectIt->mEffectID].push_back (effectInfo); + } + } + + parent->setVisible(effects.size() != 0); + + int w=2; + if (adjustSize) + { + int s = effects.size() * 16+4; + int diff = parent->getWidth() - s; + parent->setSize(s, parent->getHeight()); + parent->setPosition(parent->getLeft()+diff, parent->getTop()); + } + + + for (std::map >::const_iterator it = effects.begin(); it != effects.end(); ++it) + { + MyGUI::ImageBox* image; + if (mWidgetMap.find(it->first) == mWidgetMap.end()) + image = parent->createWidget + ("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default); + else + image = mWidgetMap[it->first]; + mWidgetMap[it->first] = image; + image->setPosition(w,2); + image->setVisible(true); + + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(it->first); + + std::string icon = effect->mIcon; + icon[icon.size()-3] = 'd'; + icon[icon.size()-2] = 'd'; + icon[icon.size()-1] = 's'; + icon = "icons\\" + icon; + + image->setImageTexture(icon); + w += 16; + + float remainingDuration = 0; + + std::string sourcesDescription; + + const float fadeTime = 5.f; + + for (std::vector::const_iterator effectIt = it->second.begin(); + effectIt != it->second.end(); ++effectIt) + { + if (effectIt != it->second.begin()) + sourcesDescription += "\n"; + + // if at least one of the effect sources is permanent, the effect will never wear off + if (effectIt->mPermanent) + remainingDuration = fadeTime; + else + remainingDuration = std::max(remainingDuration, effectIt->mRemainingTime); + + sourcesDescription += effectIt->mSource; + + if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) + sourcesDescription += " (" + + MWBase::Environment::get().getWindowManager()->getGameSettingString( + ESM::Skill::sSkillNameIds[effectIt->mKey.mArg], "") + ")"; + if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + sourcesDescription += " (" + + MWBase::Environment::get().getWindowManager()->getGameSettingString( + ESM::Attribute::sGmstAttributeIds[effectIt->mKey.mArg], "") + ")"; + + if (!(effect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) + { + std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); + std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + + sourcesDescription += ": " + boost::lexical_cast(effectIt->mMagnitude); + sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? pts : pt); + } + } + + std::string name = ESM::MagicEffect::effectIdToString (it->first); + + ToolTipInfo tooltipInfo; + tooltipInfo.caption = "#{" + name + "}"; + tooltipInfo.icon = effect->mIcon; + tooltipInfo.text = sourcesDescription; + tooltipInfo.imageSize = 16; + tooltipInfo.wordWrap = false; + + image->setUserData(tooltipInfo); + image->setUserString("ToolTipType", "ToolTipInfo"); + + // Fade out during the last 5 seconds + image->setAlpha(std::min(remainingDuration/fadeTime, 1.f)); + } + + // hide inactive effects + for (std::map::iterator it = mWidgetMap.begin(); it != mWidgetMap.end(); ++it) + { + if (effects.find(it->first) == effects.end()) + it->second->setVisible(false); + } + + } + + + std::string SpellIcons::getSpellDisplayName (const std::string& id) + { + if (const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return spell->mName; + + if (const ESM::Potion *potion = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return potion->mName; + + if (const ESM::Ingredient *ingredient = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return ingredient->mName; + + throw std::runtime_error ("ID " + id + " has no display name"); + } + + ESM::EffectList SpellIcons::getSpellEffectList (const std::string& id) + { + if (const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return spell->mEffects; + + if (const ESM::Potion *potion = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + return potion->mEffects; + + if (const ESM::Ingredient *ingredient = + MWBase::Environment::get().getWorld()->getStore().get().search (id)) + { + const ESM::MagicEffect *magicEffect = + MWBase::Environment::get().getWorld()->getStore().get().find ( + ingredient->mData.mEffectID[0]); + + ESM::ENAMstruct effect; + effect.mEffectID = ingredient->mData.mEffectID[0]; + effect.mSkill = ingredient->mData.mSkills[0]; + effect.mAttribute = ingredient->mData.mAttributes[0]; + effect.mRange = 0; + effect.mArea = 0; + effect.mDuration = magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration ? 0 : 1; + effect.mMagnMin = 1; + effect.mMagnMax = 1; + ESM::EffectList result; + result.mList.push_back (effect); + return result; + } + throw std::runtime_error("ID " + id + " does not have effects"); + } + +} diff --git a/apps/openmw/mwgui/spellicons.hpp b/apps/openmw/mwgui/spellicons.hpp new file mode 100644 index 000000000..af600e347 --- /dev/null +++ b/apps/openmw/mwgui/spellicons.hpp @@ -0,0 +1,47 @@ +#ifndef MWGUI_SPELLICONS_H +#define MWGUI_SPELLICONS_H + +#include + +#include "../mwmechanics/magiceffects.hpp" + +namespace MyGUI +{ + class Widget; + class ImageBox; +} +namespace ESM +{ + struct ENAMstruct; + struct EffectList; +} + +namespace MWGui +{ + + // information about a single magic effect source as required for display in the tooltip + struct MagicEffectInfo + { + MagicEffectInfo() : mPermanent(false) {} + std::string mSource; // display name for effect source (e.g. potion name) + MWMechanics::EffectKey mKey; + int mMagnitude; + float mRemainingTime; + bool mPermanent; // the effect is permanent + }; + + class SpellIcons + { + public: + void updateWidgets(MyGUI::Widget* parent, bool adjustSize); + + private: + std::string getSpellDisplayName (const std::string& id); + ESM::EffectList getSpellEffectList (const std::string& id); + + std::map mWidgetMap; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 47e1d739a..50691d554 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -19,6 +19,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" +#include "spellicons.hpp" #include "inventorywindow.hpp" #include "confirmationdialog.hpp" @@ -51,6 +52,8 @@ namespace MWGui , mHeight(0) , mWidth(0) { + mSpellIcons = new SpellIcons(); + getWidget(mSpellView, "SpellView"); getWidget(mEffectBox, "EffectsBox"); @@ -61,6 +64,11 @@ namespace MWGui mMainWidget->castType()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize); } + SpellWindow::~SpellWindow() + { + delete mSpellIcons; + } + void SpellWindow::onPinToggled() { mWindowManager.setSpellVisibility(!mPinned); @@ -73,6 +81,8 @@ namespace MWGui void SpellWindow::updateSpells() { + mSpellIcons->updateWidgets(mEffectBox, false); + const int spellHeight = 18; mHeight = 0; diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index caa67fd74..1963d4346 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -5,10 +5,13 @@ namespace MWGui { + class SpellIcons; + class SpellWindow : public WindowPinnableBase { public: SpellWindow(MWBase::WindowManager& parWindowManager); + virtual ~SpellWindow(); void updateSpells(); @@ -33,6 +36,8 @@ namespace MWGui virtual void onPinToggled(); virtual void open(); + + SpellIcons* mSpellIcons; }; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c7acf568d..b42f9ac25 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -127,9 +127,7 @@ void ToolTips::onFrame(float frameDuration) Widget* focus = InputManager::getInstance().getMouseFocusWidget(); if (focus == 0) - { return; - } IntSize tooltipSize; @@ -168,6 +166,10 @@ void ToolTips::onFrame(float frameDuration) mFocusObject = *focus->getUserData(); tooltipSize = getToolTipViaPtr(false); } + else if (type == "ToolTipInfo") + { + tooltipSize = createToolTip(*focus->getUserData()); + } else if (type == "AvatarItemSelection") { MyGUI::IntCoord avatarPos = mWindowManager->getInventoryWindow ()->getAvatarScreenCoord (); @@ -363,7 +365,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) std::string caption = info.caption; std::string image = info.icon; - int imageSize = (image != "") ? 32 : 0; + int imageSize = (image != "") ? info.imageSize : 0; std::string text = info.text; // remove the first newline (easier this way) @@ -403,7 +405,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption"); captionWidget->setProperty("Static", "true"); - captionWidget->setCaption(caption); + captionWidget->setCaptionWithReplacing(caption); IntSize captionSize = captionWidget->getTextSize(); int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); @@ -411,7 +413,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), Align::Stretch, "ToolTipText"); textWidget->setProperty("Static", "true"); textWidget->setProperty("MultiLine", "true"); - textWidget->setProperty("WordWrap", "true"); + textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); textWidget->setCaptionWithReplacing(text); textWidget->setTextAlign(Align::HCenter | Align::Top); IntSize textSize = textWidget->getTextSize(); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 4048d0d5a..ba94915cc 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -15,11 +15,14 @@ namespace MWGui public: ToolTipInfo() : isPotion(false) + , imageSize(32) + , wordWrap(true) {} std::string caption; std::string text; std::string icon; + int imageSize; // enchantment (for cloth, armor, weapons) std::string enchant; @@ -28,6 +31,7 @@ namespace MWGui Widgets::SpellEffectList effects; bool isPotion; // potions do not show target in the tooltip + bool wordWrap; }; class ToolTips : public OEngine::GUI::Layout diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index f932c1f03..ade681963 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -421,17 +421,7 @@ void MWSpellEffect::updateWidgets() } if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) { - static const char *attributes[8] = { - "sAttributeStrength", - "sAttributeIntelligence", - "sAttributeWillpower", - "sAttributeAgility", - "sAttributeSpeed", - "sAttributeEndurance", - "sAttributePersonality", - "sAttributeLuck" - }; - spellLine += " " + mWindowManager->getGameSettingString(attributes[mEffectParams.mAttribute], ""); + spellLine += " " + mWindowManager->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); } if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1138f62fa..0110171e6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -54,6 +54,7 @@ #include "imagebutton.hpp" #include "exposedwindow.hpp" #include "cursor.hpp" +#include "spellicons.hpp" using namespace MWGui; @@ -270,6 +271,8 @@ void WindowManager::update() mHud->setTriangleCount(mTriangleCount); mHud->setBatchCount(mBatchCount); + mHud->update(); + mCursor->update(); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e2d64a855..4e8f12160 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -73,6 +73,7 @@ namespace MWGui class EnchantingDialog; class TrainingWindow; class Cursor; + class SpellIcons; class WindowManager : public MWBase::WindowManager { diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index ee1e9da36..933c5094d 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -274,4 +274,9 @@ namespace MWMechanics } return false; } + + const ActiveSpells::TContainer& ActiveSpells::getActiveSpells() const + { + return mSpells; + } } diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 6b832f4cd..05aa2bbdd 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -63,6 +63,8 @@ namespace MWMechanics const MagicEffects& getMagicEffects() const; + const TContainer& getActiveSpells() const; + TIterator begin() const; TIterator end() const; diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index e4c6f0765..382bc6dc9 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -61,10 +61,7 @@ - - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index 23480e8d3..f847ca51a 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -16,6 +16,10 @@
+ + + + diff --git a/files/mygui/openmw_spell_window.layout b/files/mygui/openmw_spell_window.layout index 6c6629605..18a5af352 100644 --- a/files/mygui/openmw_spell_window.layout +++ b/files/mygui/openmw_spell_window.layout @@ -4,8 +4,8 @@ - - + + From 8e05c4159d309259cd31fd30181e1593d0e02ffb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 12:17:37 +0100 Subject: [PATCH 857/916] Magic effect icons for permanent enchantments --- apps/openmw/mwgui/spellicons.cpp | 40 ++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 19b2a87ec..dcbbed49c 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -12,6 +12,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwmechanics/activespells.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -29,6 +30,41 @@ namespace MWGui std::map > effects; + // add permanent item enchantments + MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = store.getSlot(slot); + if (it == store.end()) + continue; + std::string enchantment = MWWorld::Class::get(*it).getEnchantment(*it); + if (enchantment.empty()) + continue; + const ESM::Enchantment* enchant = MWBase::Environment::get().getWorld()->getStore().get().find(enchantment); + if (enchant->mData.mType != ESM::Enchantment::ConstantEffect) + continue; + + const ESM::EffectList& list = enchant->mEffects; + for (std::vector::const_iterator effectIt = list.mList.begin(); + effectIt != list.mList.end(); ++effectIt) + { + const ESM::MagicEffect* magicEffect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(effectIt->mEffectID); + + MagicEffectInfo effectInfo; + effectInfo.mSource = MWWorld::Class::get(*it).getName(*it); + effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID); + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + effectInfo.mKey.mArg = effectIt->mSkill; + else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + effectInfo.mKey.mArg = effectIt->mAttribute; + // just using the min magnitude here, permanent enchantments with a random magnitude just wouldn't make any sense + effectInfo.mMagnitude = effectIt->mMagnMin; + effectInfo.mPermanent = true; + effects[effectIt->mEffectID].push_back (effectInfo); + } + } + // add permanent spells const MWMechanics::Spells& spells = stats.getSpells(); for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) @@ -41,7 +77,7 @@ namespace MWGui && !(spell->mData.mType == ESM::Spell::ST_Curse) && !(spell->mData.mType == ESM::Spell::ST_Blight)) continue; - ESM::EffectList list = spell->mEffects; + const ESM::EffectList& list = spell->mEffects; for (std::vector::const_iterator effectIt = list.mList.begin(); effectIt != list.mList.end(); ++effectIt) { @@ -67,7 +103,7 @@ namespace MWGui for (MWMechanics::ActiveSpells::TContainer::const_iterator it = activeSpells.begin(); it != activeSpells.end(); ++it) { - ESM::EffectList list = getSpellEffectList(it->first); + const ESM::EffectList& list = getSpellEffectList(it->first); float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); From 6f05c4229f9183c04687fba5cc172bddb6e475d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 12:41:37 +0100 Subject: [PATCH 858/916] Implemented potion & ingredient effect stacking --- apps/openmw/mwmechanics/activespells.cpp | 32 +++++++++++++----------- apps/openmw/mwmechanics/activespells.hpp | 5 ++-- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 933c5094d..9aca6b7b7 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -62,7 +62,7 @@ namespace MWMechanics for (TIterator iter (begin()); iter!=end(); ++iter) { - std::pair effects = getEffectList (iter->first); + std::pair > effects = getEffectList (iter->first); const MWWorld::TimeStamp& start = iter->second.first; float magnitude = iter->second.second; @@ -74,7 +74,7 @@ namespace MWMechanics { int duration = iter->mDuration; - if (effects.second) + if (effects.second.first) duration *= magnitude; MWWorld::TimeStamp end = start; @@ -85,7 +85,7 @@ namespace MWMechanics { EffectParam param; - if (effects.second) + if (effects.second.first) { const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find ( @@ -113,15 +113,15 @@ namespace MWMechanics } } - std::pair ActiveSpells::getEffectList (const std::string& id) const + std::pair > ActiveSpells::getEffectList (const std::string& id) const { if (const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().search (id)) - return std::make_pair (spell->mEffects, false); + return std::make_pair (spell->mEffects, std::make_pair(false, false)); if (const ESM::Potion *potion = MWBase::Environment::get().getWorld()->getStore().get().search (id)) - return std::make_pair (potion->mEffects, false); + return std::make_pair (potion->mEffects, std::make_pair(false, true)); if (const ESM::Ingredient *ingredient = MWBase::Environment::get().getWorld()->getStore().get().search (id)) @@ -140,11 +140,12 @@ namespace MWMechanics effect.mMagnMin = 1; effect.mMagnMax = 1; - std::pair result; - + std::pair > result; + result.second.second = true; + result.second.first = true; + result.first.mList.push_back (effect); - result.second = true; - + return result; } @@ -157,7 +158,8 @@ namespace MWMechanics bool ActiveSpells::addSpell (const std::string& id, const MWWorld::Ptr& actor) { - std::pair effects = getEffectList (id); + std::pair > effects = getEffectList (id); + bool stacks = effects.second.second; bool found = false; @@ -178,7 +180,7 @@ namespace MWMechanics float random = static_cast (std::rand()) / RAND_MAX; - if (effects.second) + if (effects.second.first) { // ingredient -> special treatment required. const CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); @@ -194,7 +196,7 @@ namespace MWMechanics random *= 0.25 * x; } - if (iter==mSpells.end()) + if (iter==mSpells.end() || stacks) mSpells.insert (std::make_pair (id, std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random))); else @@ -236,7 +238,7 @@ namespace MWMechanics double ActiveSpells::timeToExpire (const TIterator& iterator) const { - std::pair effects = getEffectList (iterator->first); + std::pair > effects = getEffectList (iterator->first); int duration = 0; @@ -247,7 +249,7 @@ namespace MWMechanics duration = iter->mDuration; } - if (effects.second) + if (effects.second.first) duration *= iterator->second.second; double scaledDuration = duration * diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 05aa2bbdd..8c859b2cb 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -30,7 +30,7 @@ namespace MWMechanics { public: - typedef std::map > TContainer; + typedef std::multimap > TContainer; typedef TContainer::const_iterator TIterator; private: @@ -44,7 +44,8 @@ namespace MWMechanics void rebuildEffects() const; - std::pair getEffectList (const std::string& id) const; + std::pair > getEffectList (const std::string& id) const; + ///< @return (EffectList, (isIngredient, stacks)) public: From 6037c44ea6850595bace11f5f0bde64f5ae8f31e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 12:41:57 +0100 Subject: [PATCH 859/916] Fix ingredient effect display --- apps/openmw/mwgui/spellicons.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index dcbbed49c..16e02ebba 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -124,6 +124,17 @@ namespace MWGui effectInfo.mRemainingTime = effectIt->mDuration + (it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + // ingredients need special casing for their magnitude / duration + /// \todo duplicated from ActiveSpells, helper function? + if (MWBase::Environment::get().getWorld()->getStore().get().search (it->first)) + { + effectInfo.mRemainingTime = effectIt->mDuration * it->second.second + + (it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + + effectInfo.mMagnitude = static_cast (0.05*it->second.second / (0.1 * magicEffect->mData.mBaseCost)); + } + + effects[effectIt->mEffectID].push_back (effectInfo); } } From 9a84f6744f561a4e8dd1e86d652602dae19ca330 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 13:11:02 +0100 Subject: [PATCH 860/916] Fix headers including whole MyGUI.h, forward declare where appropriate, and fix some deprecated types (WidgetPtr) --- apps/openmw/mwgui/alchemywindow.cpp | 2 +- apps/openmw/mwgui/birth.cpp | 12 +++--- apps/openmw/mwgui/birth.hpp | 4 +- apps/openmw/mwgui/class.cpp | 56 +++++++++++++------------- apps/openmw/mwgui/class.hpp | 18 ++++----- apps/openmw/mwgui/console.cpp | 4 +- apps/openmw/mwgui/console.hpp | 8 ++-- apps/openmw/mwgui/cursor.cpp | 4 +- apps/openmw/mwgui/dialogue.cpp | 6 +-- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/exposedwindow.cpp | 4 +- apps/openmw/mwgui/exposedwindow.hpp | 2 +- apps/openmw/mwgui/hud.cpp | 4 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/imagebutton.hpp | 2 +- apps/openmw/mwgui/journalwindow.hpp | 4 +- apps/openmw/mwgui/list.cpp | 5 ++- apps/openmw/mwgui/list.hpp | 7 +++- apps/openmw/mwgui/messagebox.cpp | 10 ++--- apps/openmw/mwgui/messagebox.hpp | 16 +++++--- apps/openmw/mwgui/race.cpp | 16 ++++---- apps/openmw/mwgui/race.hpp | 8 ++-- apps/openmw/mwgui/review.cpp | 6 +-- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/stats_window.cpp | 4 +- apps/openmw/mwgui/stats_window.hpp | 4 +- apps/openmw/mwgui/text_input.cpp | 4 +- apps/openmw/mwgui/text_input.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 4 +- apps/openmw/mwgui/widgets.cpp | 47 +++++++++++---------- apps/openmw/mwgui/widgets.hpp | 22 ++++++---- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- libs/openengine/gui/manager.cpp | 9 +++-- libs/openengine/gui/manager.hpp | 2 + 34 files changed, 166 insertions(+), 138 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index db1a81c2c..fce612600 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -237,7 +237,7 @@ namespace MWGui Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list); effectsWidget->setEffectList(_list); - std::vector effectItems; + std::vector effectItems; effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0); effectsWidget->setCoord(coord); } diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 53e5c022d..4b07dd698 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -40,11 +40,11 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); @@ -55,7 +55,7 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) void BirthDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) @@ -82,7 +82,7 @@ void BirthDialog::setBirthId(const std::string &birthId) if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) { mBirthList->setIndexSelected(i); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); break; } @@ -110,7 +110,7 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); const std::string *birthId = mBirthList->getItemDataAt(_index); @@ -159,7 +159,7 @@ void BirthDialog::updateBirths() void BirthDialog::updateSpells() { - for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) + for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index ad1c0b40f..d3f82dace 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -46,9 +46,9 @@ namespace MWGui void updateSpells(); MyGUI::ListBox* mBirthList; - MyGUI::WidgetPtr mSpellArea; + MyGUI::Widget* mSpellArea; MyGUI::ImageBox* mBirthImage; - std::vector mSpellItems; + std::vector mSpellItems; std::string mCurrentBirthId; }; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index f3bac898b..a2f09096a 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -31,11 +31,11 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW getWidget(mClassImage, "ClassImage"); getWidget(mClassName, "ClassName"); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); @@ -97,11 +97,11 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) getWidget(mClassImage, "ClassImage"); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); @@ -111,7 +111,7 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) void PickClassDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) @@ -138,7 +138,7 @@ void PickClassDialog::setClassId(const std::string &classId) if (boost::iequals(*mClassList->getItemDataAt(i), classId)) { mClassList->setIndexSelected(i); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); break; } @@ -166,7 +166,7 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); const std::string *classId = mClassList->getItemDataAt(_index); @@ -256,7 +256,7 @@ void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) widget->setSize(size); } -void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) +void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) { size_t count = widget->getChildCount(); int pos = 0; @@ -264,7 +264,7 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) int width = 0; for (unsigned i = 0; i < count; ++i) { - MyGUI::WidgetPtr child = widget->getChildAt(i); + MyGUI::Widget* child = widget->getChildAt(i); if (!child->getVisible()) continue; @@ -302,7 +302,7 @@ std::string InfoBoxDialog::getText() const void InfoBoxDialog::setButtons(ButtonList &buttons) { - for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) + for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } @@ -310,7 +310,7 @@ void InfoBoxDialog::setButtons(ButtonList &buttons) mCurrentButton = -1; // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget - MyGUI::ButtonPtr button; + MyGUI::Button* button; MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); ButtonList::const_iterator end = buttons.end(); for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) @@ -342,11 +342,11 @@ int InfoBoxDialog::getChosenButton() const return mCurrentButton; } -void InfoBoxDialog::onButtonClicked(MyGUI::WidgetPtr _sender) +void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) { - std::vector::const_iterator end = mButtons.end(); + std::vector::const_iterator end = mButtons.end(); int i = 0; - for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) + for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) { if (*it == _sender) { @@ -376,10 +376,10 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) : WindowModal("openmw_chargen_create_class.layout", parWindowManager) - , mSpecDialog(nullptr) - , mAttribDialog(nullptr) - , mSkillDialog(nullptr) - , mDescDialog(nullptr) + , mSpecDialog(NULL) + , mAttribDialog(NULL) + , mSkillDialog(NULL) + , mDescDialog(NULL) { // Centre dialog center(); @@ -420,15 +420,15 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); - MyGUI::ButtonPtr descriptionButton; + MyGUI::Button* descriptionButton; getWidget(descriptionButton, "DescriptionButton"); descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); @@ -518,7 +518,7 @@ std::vector CreateClassDialog::getMinorSkills() const void CreateClassDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) @@ -544,7 +544,7 @@ void CreateClassDialog::onDialogCancel() mDescDialog = 0; } -void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) +void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) { delete mSpecDialog; mSpecDialog = new SelectSpecializationDialog(mWindowManager); @@ -694,7 +694,7 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); - MyGUI::ButtonPtr cancelButton; + MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); @@ -706,7 +706,7 @@ SelectSpecializationDialog::~SelectSpecializationDialog() // widget controls -void SelectSpecializationDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) +void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender) { if (_sender == mSpecialization0) mSpecializationId = ESM::Class::Combat; @@ -747,7 +747,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); } - MyGUI::ButtonPtr cancelButton; + MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); @@ -840,7 +840,7 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) } } - MyGUI::ButtonPtr cancelButton; + MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); @@ -873,7 +873,7 @@ DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) getWidget(mTextEdit, "TextEdit"); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", "")); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 2662d94cc..8c60331d8 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_CLASS_H #define MWGUI_CLASS_H -#include + #include "widgets.hpp" #include "window_base.hpp" @@ -35,17 +35,17 @@ namespace MWGui EventHandle_Int eventButtonSelected; protected: - void onButtonClicked(MyGUI::WidgetPtr _sender); + void onButtonClicked(MyGUI::Widget* _sender); private: void fitToText(MyGUI::TextBox* widget); - void layoutVertically(MyGUI::WidgetPtr widget, int margin); + void layoutVertically(MyGUI::Widget* widget, int margin); int mCurrentButton; - MyGUI::WidgetPtr mTextBox; + MyGUI::Widget* mTextBox; MyGUI::TextBox* mText; - MyGUI::WidgetPtr mButtonBar; - std::vector mButtons; + MyGUI::Widget* mButtonBar; + std::vector mButtons; }; // Lets the player choose between 3 ways of creating a class @@ -235,7 +235,7 @@ namespace MWGui void onOkClicked(MyGUI::Widget* _sender); private: - MyGUI::EditPtr mTextEdit; + MyGUI::EditBox* mTextEdit; }; class CreateClassDialog : public WindowModal @@ -265,7 +265,7 @@ namespace MWGui void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); - void onSpecializationClicked(MyGUI::WidgetPtr _sender); + void onSpecializationClicked(MyGUI::Widget* _sender); void onSpecializationSelected(); void onAttributeClicked(Widgets::MWAttributePtr _sender); void onAttributeSelected(); @@ -280,7 +280,7 @@ namespace MWGui void update(); private: - MyGUI::EditPtr mEditName; + MyGUI::EditBox* mEditName; MyGUI::TextBox* mSpecializationName; Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1; Widgets::MWSkillPtr mMajorSkill[5]; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index b2281d87e..1aebe57da 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -216,7 +216,7 @@ namespace MWGui } } - void Console::keyPress(MyGUI::WidgetPtr _sender, + void Console::keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char) { @@ -266,7 +266,7 @@ namespace MWGui } } - void Console::acceptCommand(MyGUI::EditPtr _sender) + void Console::acceptCommand(MyGUI::EditBox* _sender) { const std::string &cm = command->getCaption(); if(cm.empty()) return; diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index 1893b0148..b1d961ed2 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -55,8 +55,8 @@ namespace MWGui public: - MyGUI::EditPtr command; - MyGUI::EditPtr history; + MyGUI::EditBox* command; + MyGUI::EditBox* history; typedef std::list StringList; @@ -95,11 +95,11 @@ namespace MWGui private: - void keyPress(MyGUI::WidgetPtr _sender, + void keyPress(MyGUI::Widget* _sender, MyGUI::KeyCode key, MyGUI::Char _char); - void acceptCommand(MyGUI::EditPtr _sender); + void acceptCommand(MyGUI::EditBox* _sender); std::string complete( std::string input, std::vector &matches ); }; diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 15f61d5b6..399695ae3 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -14,7 +14,7 @@ namespace MWGui ResourceImageSetPointerFix::ResourceImageSetPointerFix() : - mImageSet(nullptr) + mImageSet(NULL) { } @@ -50,7 +50,7 @@ namespace MWGui void ResourceImageSetPointerFix::setImage(MyGUI::ImageBox* _image) { - if (mImageSet != nullptr) + if (mImageSet != NULL) _image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0)); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index c7918ceb7..859e3008c 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -151,7 +151,7 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) getWidget(mTopicsList, "TopicsList"); mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - MyGUI::ButtonPtr byeButton; + MyGUI::Button* byeButton; getWidget(byeButton, "ByeButton"); byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); @@ -164,7 +164,7 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) { MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); - if(t == nullptr) + if(t == NULL) return; const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); @@ -381,7 +381,7 @@ std::string DialogueWindow::parseText(const std::string& text) std::vector hypertext = MWDialogue::ParseHyperText(text); size_t historySize = 0; - if(mHistory->getClient()->getSubWidgetText() != nullptr) + if(mHistory->getClient()->getSubWidgetText() != NULL) { historySize = mHistory->getOnlyText().size(); } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 5c11c311a..e39cecc3c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -113,7 +113,7 @@ namespace MWGui DialogueHistory* mHistory; Widgets::MWList* mTopicsList; MyGUI::ProgressPtr mDispositionBar; - MyGUI::EditPtr mDispositionText; + MyGUI::EditBox* mDispositionText; PersuasionDialog mPersuasionDialog; diff --git a/apps/openmw/mwgui/exposedwindow.cpp b/apps/openmw/mwgui/exposedwindow.cpp index fa37568d7..150a8c893 100644 --- a/apps/openmw/mwgui/exposedwindow.cpp +++ b/apps/openmw/mwgui/exposedwindow.cpp @@ -1,7 +1,5 @@ #include "exposedwindow.hpp" -#include "MyGUI_Window.h" - namespace MWGui { MyGUI::VectorWidgetPtr ExposedWindow::getSkinWidgetsByName (const std::string &name) @@ -16,7 +14,7 @@ namespace MWGui if (widgets.empty()) { MYGUI_ASSERT( ! _throw, "widget name '" << _name << "' not found in skin of layout '" << getName() << "'"); - return nullptr; + return NULL; } else { diff --git a/apps/openmw/mwgui/exposedwindow.hpp b/apps/openmw/mwgui/exposedwindow.hpp index 906d0b406..7df2fcb35 100644 --- a/apps/openmw/mwgui/exposedwindow.hpp +++ b/apps/openmw/mwgui/exposedwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_EXPOSEDWINDOW_H #define MWGUI_EXPOSEDWINDOW_H -#include "MyGUI_Window.h" +#include namespace MWGui { diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index a2c3a318b..7cb0f3924 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -2,7 +2,9 @@ #include -#include +#include +#include +#include #include diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 013ad59f0..51dcffb09 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -60,7 +60,7 @@ namespace MWGui MyGUI::Widget* mDummy; - MyGUI::WidgetPtr mFpsBox; + MyGUI::Widget* mFpsBox; MyGUI::TextBox* mFpsCounter; MyGUI::TextBox* mTriangleCounter; MyGUI::TextBox* mBatchCounter; diff --git a/apps/openmw/mwgui/imagebutton.hpp b/apps/openmw/mwgui/imagebutton.hpp index 9fce12da1..f531e2246 100644 --- a/apps/openmw/mwgui/imagebutton.hpp +++ b/apps/openmw/mwgui/imagebutton.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_IMAGEBUTTON_H #define MWGUI_IMAGEBUTTON_H -#include "MyGUI_ImageBox.h" +#include namespace MWGui { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 044a2b2a4..cd1ff7ebb 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -29,8 +29,8 @@ namespace MWGui void notifyNextPage(MyGUI::Widget* _sender); void notifyPrevPage(MyGUI::Widget* _sender); - MyGUI::EditPtr mLeftTextWidget; - MyGUI::EditPtr mRightTextWidget; + MyGUI::EditBox* mLeftTextWidget; + MyGUI::EditBox* mRightTextWidget; MWGui::ImageButton* mPrevBtn; MWGui::ImageButton* mNextBtn; std::vector mLeftPages; diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index 0bafced97..d60e9b687 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -1,6 +1,9 @@ #include "list.hpp" -#include +#include +#include +#include +#include using namespace MWGui; using namespace MWGui::Widgets; diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index d07d49de6..38797e779 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -1,7 +1,12 @@ #ifndef MWGUI_LIST_HPP #define MWGUI_LIST_HPP -#include +#include + +namespace MyGUI +{ + class ScrollView; +} namespace MWGui { diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 0ee042e32..b8a34c457 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -247,7 +247,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan std::vector::const_iterator it; for(it = buttons.begin(); it != buttons.end(); ++it) { - MyGUI::ButtonPtr button = mButtonsWidget->createWidget( + MyGUI::Button* button = mButtonsWidget->createWidget( MyGUI::WidgetStyle::Child, std::string("MW_Button"), dummyCoord, @@ -301,7 +301,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan MyGUI::IntSize buttonSize(0, buttonHeight); int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; - std::vector::const_iterator button; + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { buttonCord.left = left; @@ -349,7 +349,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan int top = textButtonPadding + buttonTopPadding + textSize.height; - std::vector::const_iterator button; + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; @@ -371,7 +371,7 @@ void InteractiveMessageBox::enterPressed() { std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) @@ -393,7 +393,7 @@ void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) { mMarkedToDelete = true; int index = 0; - std::vector::const_iterator button; + std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { if(*button == pressed) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 4be8bc5b7..149aa7e7f 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -2,7 +2,6 @@ #define MWGUI_MESSAGE_BOX_H #include -#include #include "window_base.hpp" @@ -10,6 +9,13 @@ #undef MessageBox +namespace MyGUI +{ + class Widget; + class Button; + class EditBox; +} + namespace MWGui { class InteractiveMessageBox; @@ -61,7 +67,7 @@ namespace MWGui MessageBoxManager& mMessageBoxManager; int mHeight; const std::string& mMessage; - MyGUI::EditPtr mMessageWidget; + MyGUI::EditBox* mMessageWidget; int mFixedWidth; int mBottomPadding; int mNextBoxPadding; @@ -81,9 +87,9 @@ namespace MWGui void buttonActivated (MyGUI::Widget* _widget); MessageBoxManager& mMessageBoxManager; - MyGUI::EditPtr mMessageWidget; - MyGUI::WidgetPtr mButtonsWidget; - std::vector mButtons; + MyGUI::EditBox* mMessageWidget; + MyGUI::Widget* mButtonsWidget; + std::vector mButtons; int mTextButtonPadding; int mButtonPressed; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 71a4d1b3e..1436995c5 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -41,7 +41,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); // Set up next/previous buttons - MyGUI::ButtonPtr prevButton, nextButton; + MyGUI::Button *prevButton, *nextButton; setText("GenderChoiceT", mWindowManager.getGameSettingString("sRaceMenu2", "Change Sex")); getWidget(prevButton, "PrevGenderButton"); @@ -73,11 +73,11 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials")); getWidget(mSpellPowerList, "SpellPowerList"); - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); @@ -89,7 +89,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) void RaceDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) @@ -134,7 +134,7 @@ void RaceDialog::setRaceId(const std::string &raceId) if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) { mRaceList->setIndexSelected(i); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); break; } @@ -256,7 +256,7 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); const std::string *raceId = mRaceList->getItemDataAt(_index); if (boost::iequals(mCurrentRaceId, *raceId)) @@ -331,7 +331,7 @@ void RaceDialog::updateRaces() void RaceDialog::updateSkills() { - for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) + for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } @@ -369,7 +369,7 @@ void RaceDialog::updateSkills() void RaceDialog::updateSpellPowers() { - for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) + for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 619556906..efd08f439 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -85,11 +85,11 @@ namespace MWGui MyGUI::ListBox* mRaceList; MyGUI::ScrollBar* mHeadRotate; - MyGUI::WidgetPtr mSkillList; - std::vector mSkillItems; + MyGUI::Widget* mSkillList; + std::vector mSkillItems; - MyGUI::WidgetPtr mSpellPowerList; - std::vector mSpellPowerItems; + MyGUI::Widget* mSpellPowerList; + std::vector mSpellPowerItems; int mGenderIndex, mFaceIndex, mHairIndex; int mFaceCount, mHairCount; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 50dc26e42..50508cc5f 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -86,11 +86,11 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); } - MyGUI::ButtonPtr backButton; + MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); } @@ -309,7 +309,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId void ReviewDialog::updateSkillArea() { - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index aac609a64..4f41ec42d 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -91,7 +91,7 @@ namespace MWGui std::map mSkillWidgetMap; std::string mName, mRaceId, mBirthSignId; ESM::Class mKlass; - std::vector mSkillWidgets; //< Skills and other information + std::vector mSkillWidgets; //< Skills and other information }; } #endif diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 70ceed857..0fa4127b5 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -67,7 +67,7 @@ StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) for (int i = 0; i < ESM::Skill::Length; ++i) { mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)nullptr)); + mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); } MyGUI::WindowPtr t = static_cast(mMainWidget); @@ -419,7 +419,7 @@ void StatsWindow::updateSkillArea() { mChanged = false; - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 6619680fa..3befc1f00 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -67,11 +67,11 @@ namespace MWGui SkillList mMajorSkills, mMinorSkills, mMiscSkills; std::map > mSkillValues; std::map mSkillWidgetMap; - std::map mFactionWidgetMap; + std::map mFactionWidgetMap; FactionList mFactions; ///< Stores a list of factions and the current rank std::string mBirthSignId; int mReputation, mBounty; - std::vector mSkillWidgets; //< Skills and other information + std::vector mSkillWidgets; //< Skills and other information std::set mExpelled; bool mChanged; diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index c19394833..9265cadf9 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -13,7 +13,7 @@ TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) getWidget(mTextEdit, "TextEdit"); mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); @@ -23,7 +23,7 @@ TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) void TextInputDialog::setNextButtonShow(bool shown) { - MyGUI::ButtonPtr okButton; + MyGUI::Button* okButton; getWidget(okButton, "OKButton"); if (shown) diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp index 649990281..29de7388b 100644 --- a/apps/openmw/mwgui/text_input.hpp +++ b/apps/openmw/mwgui/text_input.hpp @@ -30,7 +30,7 @@ namespace MWGui void onTextAccepted(MyGUI::Edit* _sender); private: - MyGUI::EditPtr mTextEdit; + MyGUI::EditBox* mTextEdit; }; } #endif diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index c7acf568d..261a7f8bd 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -439,7 +439,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) effectsWidget->setWindowManager(mWindowManager); effectsWidget->setEffectList(info.effects); - std::vector effectItems; + std::vector effectItems; effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, info.isPotion ? Widgets::MWEffectList::EF_NoTarget : 0); totalSize.height += coord.top-6; totalSize.width = std::max(totalSize.width, coord.width); @@ -459,7 +459,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) enchantWidget->setWindowManager(mWindowManager); enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); - std::vector enchantEffectItems; + std::vector enchantEffectItems; int flag = (enchant->mData.mType == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, flag); totalSize.height += coord.top-6; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index f932c1f03..8857ecfa3 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -31,10 +34,10 @@ void MWGui::Widgets::fixTexturePath(std::string &path) /* MWSkill */ MWSkill::MWSkill() - : mManager(nullptr) + : mManager(NULL) , mSkillId(ESM::Skill::Length) - , mSkillNameWidget(nullptr) - , mSkillValueWidget(nullptr) + , mSkillNameWidget(NULL) + , mSkillValueWidget(NULL) { } @@ -103,7 +106,7 @@ void MWSkill::initialiseOverride() assignWidget(mSkillNameWidget, "StatName"); assignWidget(mSkillValueWidget, "StatValue"); - MyGUI::ButtonPtr button; + MyGUI::Button* button; assignWidget(button, "StatNameButton"); if (button) { @@ -123,10 +126,10 @@ void MWSkill::initialiseOverride() /* MWAttribute */ MWAttribute::MWAttribute() - : mManager(nullptr) + : mManager(NULL) , mId(-1) - , mAttributeNameWidget(nullptr) - , mAttributeValueWidget(nullptr) + , mAttributeNameWidget(NULL) + , mAttributeValueWidget(NULL) { } @@ -195,7 +198,7 @@ void MWAttribute::initialiseOverride() assignWidget(mAttributeNameWidget, "StatName"); assignWidget(mAttributeValueWidget, "StatValue"); - MyGUI::ButtonPtr button; + MyGUI::Button* button; assignWidget(button, "StatNameButton"); if (button) { @@ -215,8 +218,8 @@ void MWAttribute::initialiseOverride() /* MWSpell */ MWSpell::MWSpell() - : mWindowManager(nullptr) - , mSpellNameWidget(nullptr) + : mWindowManager(NULL) + , mSpellNameWidget(NULL) { } @@ -226,7 +229,7 @@ void MWSpell::setSpellId(const std::string &spellId) updateWidgets(); } -void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags) +void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -234,7 +237,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: const ESM::Spell *spell = store.get().search(mId); MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); - MWSpellEffectPtr effect = nullptr; + MWSpellEffectPtr effect = NULL; std::vector::const_iterator end = spell->mEffects.mList.end(); for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) { @@ -286,7 +289,7 @@ MWSpell::~MWSpell() /* MWEffectList */ MWEffectList::MWEffectList() - : mWindowManager(nullptr) + : mWindowManager(NULL) , mEffectList(0) { } @@ -297,11 +300,11 @@ void MWEffectList::setEffectList(const SpellEffectList& list) updateWidgets(); } -void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags) +void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, bool center, int flags) { // We don't know the width of all the elements beforehand, so we do it in // 2 steps: first, create all widgets and check their width.... - MWSpellEffectPtr effect = nullptr; + MWSpellEffectPtr effect = NULL; int maxwidth = coord.width; for (SpellEffectList::iterator it=mEffectList.begin(); @@ -320,7 +323,7 @@ void MWEffectList::createEffectWidgets(std::vector &effects, M } // ... then adjust the size for all widgets - for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) + for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) { effect = static_cast(*it); bool needcenter = center && (maxwidth > effect->getRequestedWidth()); @@ -375,9 +378,9 @@ SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() - : mWindowManager(nullptr) - , mImageWidget(nullptr) - , mTextWidget(nullptr) + : mWindowManager(NULL) + , mImageWidget(NULL) + , mTextWidget(NULL) , mRequestedWidth(0) { } @@ -495,9 +498,9 @@ void MWSpellEffect::initialiseOverride() MWDynamicStat::MWDynamicStat() : mValue(0) , mMax(1) -, mTextWidget(nullptr) -, mBarWidget(nullptr) -, mBarTextWidget(nullptr) +, mTextWidget(NULL) +, mBarWidget(NULL) +, mBarTextWidget(NULL) { } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 7cbb5e53a..597bcbe32 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -2,11 +2,17 @@ #define MWGUI_WIDGETS_H #include "../mwworld/esmstore.hpp" - -#include - #include "../mwmechanics/stat.hpp" +#include +#include +#include + +namespace MyGUI +{ + class ImageBox; +} + namespace MWBase { class WindowManager; @@ -118,7 +124,8 @@ namespace MWGui MWBase::WindowManager *mManager; ESM::Skill::SkillEnum mSkillId; SkillValue mValue; - MyGUI::WidgetPtr mSkillNameWidget, mSkillValueWidget; + MyGUI::Widget* mSkillNameWidget; + MyGUI::Widget* mSkillValueWidget; }; typedef MWSkill* MWSkillPtr; @@ -160,7 +167,8 @@ namespace MWGui MWBase::WindowManager *mManager; int mId; AttributeValue mValue; - MyGUI::WidgetPtr mAttributeNameWidget, mAttributeValueWidget; + MyGUI::Widget* mAttributeNameWidget; + MyGUI::Widget* mAttributeValueWidget; }; typedef MWAttribute* MWAttributePtr; @@ -186,7 +194,7 @@ namespace MWGui * @param spell category, if this is 0, this means the spell effects are permanent and won't display e.g. duration * @param various flags, see MWEffectList::EffectFlags */ - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags); + void createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags); const std::string &getSpellId() const { return mId; } @@ -230,7 +238,7 @@ namespace MWGui * @param center the effect widgets horizontally * @param various flags, see MWEffectList::EffectFlags */ - void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags); + void createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, bool center, int flags); protected: virtual ~MWEffectList(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1138f62fa..7d5b6af6e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -3,7 +3,7 @@ #include #include -#include "MyGUI_UString.h" +#include #include #include diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index e5a164b81..07fbafa7d 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -1,9 +1,10 @@ -#include -#include -#include - #include "manager.hpp" +#include +#include + +#include + using namespace OEngine::GUI; /* diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index c0f98da88..9443fba01 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -1,6 +1,8 @@ #ifndef OENGINE_MYGUI_MANAGER_H #define OENGINE_MYGUI_MANAGER_H +#include + namespace MyGUI { class Gui; From e1882dce32c96ff773a1dbc5b92f7eef1cb71cde Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 3 Mar 2013 13:02:41 +0000 Subject: [PATCH 861/916] correcting a bug: player orientation wasn't stored correctly, and objects orientation wasn't properly retrived. --- apps/openmw/mwrender/renderingmanager.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index fe3dc776d..b214fd800 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -273,16 +273,21 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot Ogre::Quaternion xr(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X); Ogre::Quaternion yr(Ogre::Radian(rot.y), Ogre::Vector3::UNIT_Y); Ogre::Quaternion zr(Ogre::Radian(rot.z), Ogre::Vector3::UNIT_Z); - Ogre::Quaternion newo = adjust ? (xr * yr * zr) * ptr.getRefData().getBaseNode()->getOrientation() : xr * yr * zr; - rot.x = newo.x; - rot.y = newo.y; - rot.z = newo.z; + + Ogre::Quaternion xref(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yref(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zref(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); + + Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; + rot.x = newo.getPitch().valueRadians();// newo.x;Ogre::Quaternion:: + rot.y = newo.getYaw().valueRadians();//newo.y; + rot.z = newo.getRoll().valueRadians(); //newo.z; ptr.getRefData().getBaseNode()->setOrientation(newo); } else if(isPlayer) { rot.x = mPlayer->getPitch(); - rot.z = mPlayer->getYaw(); + rot.z = -mPlayer->getYaw(); } else if (adjust) { From 7fb2ff18a39d5347811ae6ca0cd7eca635688f58 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 3 Mar 2013 13:06:45 +0000 Subject: [PATCH 862/916] Fix bug induced by previous commit (player orientation wasn't stored correctly), and fix NPC not beeing able to move with certain angles (like angle Z 70) because the trace function was hitting NPC own hitboxes. The solution prposed here is a little hacky, but i works. Need a little clean up(mBody shouldn't be public) --- apps/openmw/mwworld/physicssystem.cpp | 15 ++++++++------- libs/openengine/bullet/physic.hpp | 3 ++- libs/openengine/bullet/trace.cpp | 11 ++++++++++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 65cbc1164..90c090f59 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -99,7 +99,7 @@ namespace MWWorld if(!physicActor || !physicActor->getCollisionMode()) { // FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why? - return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + return position + (Ogre::Quaternion(Ogre::Radian( refpos.rot[2]), Ogre::Vector3::UNIT_Z)* Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement; @@ -109,12 +109,13 @@ namespace MWWorld bool onground = false; float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); - Ogre::Vector3 halfExtents = physicActor->getHalfExtents(); + Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); + physicActor->mBody->translate(btVector3(0,0,1000)); Ogre::Vector3 velocity; if(!gravity) { - velocity = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + velocity = (Ogre::Quaternion(Ogre::Radian( refpos.rot[2]), Ogre::Vector3::UNIT_Z)* Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement / time; @@ -127,9 +128,7 @@ namespace MWWorld if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) onground = true; } - - velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * - movement / time; + velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::UNIT_Z)*movement / time; velocity.z += physicActor->getVerticalForce(); } @@ -148,6 +147,7 @@ namespace MWWorld // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; + //std::cout << newPosition.x << " "; remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions @@ -191,7 +191,8 @@ namespace MWWorld } physicActor->setOnGround(onground); physicActor->setVerticalForce(!onground ? clippedVelocity.z - time*627.2f : 0.0f); - + physicActor->mBody->translate(btVector3(0,0,-1000)); + //std::cout << position.x << " " << newPosition.x << " " << position.y << " " << newPosition.y << std::endl; return newPosition; } }; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index bd5d3d50a..6a7150fca 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -129,9 +129,10 @@ namespace Physic void operator delete (void * Data) { _aligned_free (Data); } #endif + OEngine::Physic::RigidBody* mBody; + private: - OEngine::Physic::RigidBody* mBody; Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 7664eb418..3abe13da4 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -8,6 +8,7 @@ #include "physic.hpp" +#define BIT(x) (1<<(x)) enum traceWorldType { @@ -24,6 +25,14 @@ enum collaborativePhysicsType Both_Physics = 3 // This object has both kinds of physics (example: activators) }; +enum collisiontypes { + COL_NOTHING = 0, //dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); From ac0a23a68d644610789f00ad1912f5443aa88937 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 14:53:47 +0100 Subject: [PATCH 863/916] Fix initialization problem --- files/materials/objects.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 88ca2d152..6495b0cb4 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -146,7 +146,7 @@ #if VERTEX_LIGHTING float3 lightDir; float d; - + lightResult = float3(0,0,0); @shForeach(@shGlobalSettingString(num_lights)) lightDir = lightPosition[@shIterator].xyz - (shInputPosition.xyz * lightPosition[@shIterator].w); d = length(lightDir); From 5951abfae2ec518e03bb343d8958b7b72c68cfe6 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 3 Mar 2013 13:59:38 +0000 Subject: [PATCH 864/916] fix some script instructions --- apps/openmw/mwscript/transformationextensions.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 2dd8f3e16..8222ef150 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -148,15 +148,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -241,15 +241,15 @@ namespace MWScript if(axis == "x") { - runtime.push(ptr.getCellRef().mPos.pos[0]); + runtime.push(ptr.getRefData().getPosition().pos[0]); } else if(axis == "y") { - runtime.push(ptr.getCellRef().mPos.pos[1]); + runtime.push(ptr.getRefData().getPosition().pos[1]); } else if(axis == "z") { - runtime.push(ptr.getCellRef().mPos.pos[2]); + runtime.push(ptr.getRefData().getPosition().pos[2]); } else throw std::runtime_error ("invalid axis: " + axis); From 11f21a19886fdb010fe6f67c1c42ececb95ee4b6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 15:10:40 +0100 Subject: [PATCH 865/916] Weather update should be before renderer update --- apps/openmw/mwworld/worldimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f8efcdbd4..cddcda68b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -974,6 +974,8 @@ namespace MWWorld void World::update (float duration, bool paused) { + mWeatherManager->update (duration); + mWorldScene->update (duration, paused); float pitch, yaw; @@ -981,8 +983,6 @@ namespace MWWorld mRendering->getPlayerData(eyepos, pitch, yaw); mPhysics->updatePlayerData(eyepos, pitch, yaw); - mWeatherManager->update (duration); - performUpdateSceneQueries (); updateWindowManager (); From 867b22ce19cad53e4e5ba3aaf9f2826b7273fe43 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 15:11:19 +0100 Subject: [PATCH 866/916] Fix a terrain glitch --- apps/openmw/mwrender/terrain.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 212dd94c3..438366873 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -42,7 +42,8 @@ namespace MWRender // We don't want any pixel error at all. Really, LOD makes no sense here - morrowind uses 65x65 verts in one cell, // so applying LOD is most certainly slower than doing no LOD at all. - mTerrainGlobals->setMaxPixelError(0); + // Setting this to 0 seems to cause glitches though. :/ + mTerrainGlobals->setMaxPixelError(1); mTerrainGlobals->setLayerBlendMapSize(32); From 002830e13bc8ce0f9a882b9b225959f3cbfb2120 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 15:11:45 +0100 Subject: [PATCH 867/916] Make sure render textures are inactive when in a cell without water --- apps/openmw/mwrender/refraction.cpp | 5 +++++ apps/openmw/mwrender/refraction.hpp | 1 + apps/openmw/mwrender/water.cpp | 6 ++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 15575362b..bb2d88865 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -99,4 +99,9 @@ namespace MWRender } } + void Refraction::setActive(bool active) + { + mRenderTarget->setActive(active); + } + } diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp index de47d6e43..b9ab8deac 100644 --- a/apps/openmw/mwrender/refraction.hpp +++ b/apps/openmw/mwrender/refraction.hpp @@ -25,6 +25,7 @@ namespace MWRender void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void setUnderwater(bool underwater) {mIsUnderwater = underwater;} + void setActive (bool active); void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index d112e17b2..c116a6384 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -372,9 +372,9 @@ void Water::updateVisible() { mWater->setVisible(mToggled && mActive); if (mReflection) - { mReflection->setActive(mToggled && mActive); - } + if (mRefraction) + mRefraction->setActive(mToggled && mActive); } void Water::update(float dt, Ogre::Vector3 player) @@ -424,6 +424,8 @@ void Water::applyRTT() mRefraction = new Refraction(mCamera); mRefraction->setHeight(mTop); } + + updateVisible(); } void Water::applyVisibilityMask() From f0e3463e9bb636e303b5d77834848f058e8b715a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 16:50:10 +0100 Subject: [PATCH 868/916] Disable assertion for comparing iterators from different containers (Bug #605) --- apps/openmw/mwworld/containerstore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index eb2a14d5b..8a7884e9e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -548,7 +548,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStoreIterator::operator++ (int bool MWWorld::ContainerStoreIterator::isEqual (const ContainerStoreIterator& iter) const { - assert (mContainer==iter.mContainer); + if (mContainer!=iter.mContainer) + return false; if (mType!=iter.mType) return false; From c9fefc7f5d245541c5d24def1e26ac7bb3cd8776 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 19:28:11 +0100 Subject: [PATCH 869/916] Simpler, more lightweight underwater effect, changed colors to match vanilla better --- apps/openmw/mwgui/settingswindow.cpp | 13 ----- apps/openmw/mwgui/settingswindow.hpp | 1 - apps/openmw/mwrender/renderconst.hpp | 3 ++ apps/openmw/mwrender/renderingmanager.cpp | 40 ++++++--------- apps/openmw/mwrender/renderingmanager.hpp | 2 +- apps/openmw/mwrender/videoplayer.cpp | 6 ++- apps/openmw/mwrender/water.cpp | 24 --------- apps/openmw/mwrender/water.hpp | 3 +- files/CMakeLists.txt | 1 - files/materials/objects.shader | 58 ++++------------------ files/materials/openmw.configuration | 1 + files/materials/terrain.shader | 55 ++------------------ files/materials/underwater.h | 4 +- files/materials/water.mat | 8 --- files/materials/water.shader | 30 ++--------- files/mygui/openmw_settings_window.layout | 7 --- files/settings-default.cfg | 2 - files/water/underwater_dome.mesh | Bin 22585 -> 0 bytes 18 files changed, 46 insertions(+), 212 deletions(-) delete mode 100644 files/water/underwater_dome.mesh diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index ebeb42ab2..04856c3ed 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -129,7 +129,6 @@ namespace MWGui getWidget(mStaticsShadows, "StaticsShadows"); getWidget(mMiscShadows, "MiscShadows"); getWidget(mShadowsDebug, "ShadowsDebug"); - getWidget(mUnderwaterButton, "UnderwaterButton"); getWidget(mControlsBox, "ControlsBox"); getWidget(mResetControlsButton, "ResetControlsButton"); getWidget(mInvertYButton, "InvertYButton"); @@ -141,7 +140,6 @@ namespace MWGui mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mInvertYButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); - mUnderwaterButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mShadersButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadersToggled); mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -236,7 +234,6 @@ namespace MWGui mReflectObjectsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect statics", "Water") ? "#{sOn}" : "#{sOff}"); mReflectActorsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect actors", "Water") ? "#{sOn}" : "#{sOff}"); mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}"); - mUnderwaterButton->setCaptionWithReplacing(Settings::Manager::getBool("underwater effect", "Water") ? "#{sOn}" : "#{sOff}"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); //mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); @@ -267,7 +264,6 @@ namespace MWGui if (!Settings::Manager::getBool("shaders", "Objects")) { mRefractionButton->setEnabled(false); - mUnderwaterButton->setEnabled (false); mShadowsEnabledButton->setEnabled(false); } @@ -389,10 +385,6 @@ namespace MWGui Settings::Manager::setBool("shader", "Water", newState); else if (_sender == mRefractionButton) Settings::Manager::setBool("refraction", "Water", newState); - else if (_sender == mUnderwaterButton) - { - Settings::Manager::setBool("underwater effect", "Water", newState); - } else if (_sender == mReflectObjectsButton) { Settings::Manager::setBool("reflect misc", "Water", newState); @@ -459,10 +451,6 @@ namespace MWGui { Settings::Manager::setBool("shaders", "Objects", false); - mUnderwaterButton->setCaptionWithReplacing("#{sOff}"); - - mUnderwaterButton->setEnabled(false); - // refraction needs shaders to display underwater fog mRefractionButton->setCaptionWithReplacing("#{sOff}"); mRefractionButton->setEnabled(false); @@ -485,7 +473,6 @@ namespace MWGui mReflectTerrainButton->setEnabled(true); mRefractionButton->setEnabled(true); - mUnderwaterButton->setEnabled(true); mShadowsEnabledButton->setEnabled(true); } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 55cc0a870..fc1ec9e36 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -50,7 +50,6 @@ namespace MWGui MyGUI::Button* mReflectTerrainButton; MyGUI::Button* mShadersButton; MyGUI::Button* mShaderModeButton; - MyGUI::Button* mUnderwaterButton; MyGUI::Button* mRefractionButton; MyGUI::Button* mShadowsEnabledButton; diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index cc3cbee29..1d2cdf1ea 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -56,6 +56,9 @@ enum VisibilityFlags RV_Debug = 512, + // overlays, we only want these on the main render target + RV_Overlay = 1024, + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 943208a66..c8b5926d9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -133,8 +133,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setGlobalSetting ("lighting", "true"); sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); sh::Factory::getInstance ().setGlobalSetting ("terrain_num_lights", Settings::Manager::getString ("num lights", "Terrain")); - sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); + sh::Factory::getInstance ().setGlobalSetting ("render_refraction", "false"); sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); @@ -355,16 +355,7 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); - /* - if (world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)) - { - mFogColour = Ogre::ColourValue(0.18039, 0.23137, 0.25490); - mFogStart = 0; - mFogEnd = 1500; - } - */ - - applyFog(); + applyFog(world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)); if(paused) { @@ -529,16 +520,20 @@ void RenderingManager::configureFog(const float density, const Ogre::ColourValue mRendering.getCamera()->setFarClipDistance ( Settings::Manager::getFloat("max viewing distance", "Viewing distance") / density ); } -void RenderingManager::applyFog () +void RenderingManager::applyFog (bool underwater) { - mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); - - mRendering.getViewport()->setBackgroundColour (mFogColour); - - mWater->setViewportBackground (mFogColour); - - sh::Factory::getInstance ().setSharedParameter ("viewportBackground", - sh::makeProperty (new sh::Vector3(mFogColour.r, mFogColour.g, mFogColour.b))); + if (!underwater) + { + mRendering.getScene()->setFog (FOG_LINEAR, mFogColour, 0, mFogStart, mFogEnd); + mRendering.getViewport()->setBackgroundColour (mFogColour); + mWater->setViewportBackground (mFogColour); + } + else + { + mRendering.getScene()->setFog (FOG_LINEAR, Ogre::ColourValue(0.18039, 0.23137, 0.25490), 0, 0, 1000); + mRendering.getViewport()->setBackgroundColour (Ogre::ColourValue(0.18039, 0.23137, 0.25490)); + mWater->setViewportBackground (Ogre::ColourValue(0.18039, 0.23137, 0.25490)); + } } void RenderingManager::setAmbientMode() @@ -784,11 +779,6 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); rebuild = true; } - else if (it->second == "underwater effect" && it->first == "Water") - { - sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); - rebuild = true; - } else if (it->second == "shaders" && it->first == "Objects") { sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 02d796fdd..49cde25a3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -208,7 +208,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList sh::Factory* mFactory; void setAmbientMode(); - void applyFog(); + void applyFog(bool underwater); void setMenuTransparency(float val); diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index a0dedb6bc..2cbc85cd3 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -17,6 +17,8 @@ #include "../mwsound/sound_decoder.hpp" #include "../mwsound/sound.hpp" +#include "renderconst.hpp" + #ifdef _WIN32 #include @@ -1067,9 +1069,9 @@ VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr) mBackgroundNode->attachObject(mBackgroundRectangle); mRectangle->setVisible(false); - mRectangle->setVisibilityFlags(0x1); + mRectangle->setVisibilityFlags(RV_Overlay); mBackgroundRectangle->setVisible(false); - mBackgroundRectangle->setVisibilityFlags(0x1); + mBackgroundRectangle->setVisibilityFlags(RV_Overlay); } VideoPlayer::~VideoPlayer() diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c116a6384..49836535f 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -4,14 +4,10 @@ #include #include #include -#include -#include -#include #include #include "sky.hpp" #include "renderingmanager.hpp" -#include "compositors.hpp" #include "ripplesimulation.hpp" #include "refraction.hpp" @@ -224,16 +220,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mWater->setMaterial(mMaterial); - /* - Ogre::Entity* underwaterDome = mSceneManager->createEntity ("underwater_dome.mesh"); - underwaterDome->setRenderQueueGroup (RQG_UnderWater); - mUnderwaterDome = mSceneManager->getRootSceneNode ()->createChildSceneNode (); - mUnderwaterDome->attachObject (underwaterDome); - mUnderwaterDome->setScale(10000,10000,10000); - mUnderwaterDome->setVisible(false); - underwaterDome->setMaterialName("Underwater_Dome"); - */ - setHeight(mTop); sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); @@ -379,21 +365,11 @@ void Water::updateVisible() void Water::update(float dt, Ogre::Vector3 player) { - /* - Ogre::Vector3 pos = mCamera->getDerivedPosition (); - pos.y = -mWaterPlane.d; - mUnderwaterDome->setPosition (pos); - */ - mWaterTimer += dt; sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - //if (player.y <= mTop) - { - //mSimulation->addImpulse(Ogre::Vector2(player.x, player.z)); - } mSimulation->update(dt, Ogre::Vector2(player.x, player.y)); if (mReflection) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index ddf6ef7ab..633a30664 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -25,6 +25,7 @@ namespace Ogre class SceneNode; class Entity; class Vector3; + class Rectangle2D; struct RenderTargetEvent; } @@ -108,8 +109,6 @@ namespace MWRender { Ogre::SceneNode *mWaterNode; Ogre::Entity *mWater; - //Ogre::SceneNode* mUnderwaterDome; - bool mIsUnderwater; bool mActive; bool mToggled; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index c29d917b8..9e65b516b 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1,7 +1,6 @@ project(resources) set(WATER_FILES - underwater_dome.mesh water_nm.png circle.png ) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 6495b0cb4..37ff17843 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -16,7 +16,7 @@ #endif -#define UNDERWATER @shGlobalSettingBool(underwater_effects) && LIGHTING +#define UNDERWATER @shGlobalSettingBool(render_refraction) #define HAS_VERTEXCOLOR @shPropertyBool(has_vertex_colour) @@ -242,18 +242,8 @@ #endif #if UNDERWATER - - shUniform(float, waterLevel) @shSharedParameter(waterLevel) - - shUniform(float4, lightDirectionWS0) @shAutoConstant(lightDirectionWS0, light_position, 0) - - shSampler2D(causticMap) - - shUniform(float, waterTimer) @shSharedParameter(waterTimer) - shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) + shUniform(float, waterLevel) @shSharedParameter(waterLevel) shUniform(float, waterEnabled) @shSharedParameter(waterEnabled) - - shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #endif #if VERTEX_LIGHTING @@ -305,13 +295,7 @@ #endif #if UNDERWATER - float3 waterEyePos = float3(1,1,1); - // NOTE: this calculation would be wrong for non-uniform scaling - float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); - caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.z >= waterLevel || waterEnabled != 1.f) - caustics = float3(1,1,1); + float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif #if !VERTEX_LIGHTING @@ -358,41 +342,17 @@ #if FOG float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - #if UNDERWATER - // regular fog only if fragment is above water - if (worldPos.z > waterLevel || waterEnabled != 1.f) - #endif + +#if UNDERWATER + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); +#else shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); +#endif + #endif // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); - -#if UNDERWATER - float fogAmount = (cameraPos.z > waterLevel) - ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) - : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); - - float3 eyeVec = normalize(cameraPos.xyz-worldPos); - - float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); - waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = float3(0.0,1.0,0.85) *waterSunGradient * 0.5; - - float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); - waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = ( float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; - watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; - - - float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); - watercolour *= darkness; - - float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); -#endif } #endif diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration index 21ac9416b..b953a9131 100644 --- a/files/materials/openmw.configuration +++ b/files/materials/openmw.configuration @@ -8,6 +8,7 @@ configuration water_reflection configuration water_refraction { viewproj_fix true + render_refraction true } configuration local_map diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index ea54bb24c..af5be42cd 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -21,7 +21,7 @@ #define NEED_DEPTH 1 #endif -#define UNDERWATER @shGlobalSettingBool(underwater_effects) && LIGHTING +#define UNDERWATER @shGlobalSettingBool(render_refraction) #define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) @@ -210,14 +210,6 @@ #if UNDERWATER shUniform(float, waterLevel) @shSharedParameter(waterLevel) - shUniform(float4, lightDirectionWS0) @shAutoConstant(lightDirectionWS0, light_position, 0) - - shSampler2D(causticMap) - - shUniform(float, waterTimer) @shSharedParameter(waterTimer) - shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) - - shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #endif @@ -242,17 +234,7 @@ float3 caustics = float3(1,1,1); #if UNDERWATER - - float3 waterEyePos = float3(1,1,1); - // NOTE: this calculation would be wrong for non-uniform scaling - float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); - waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); - caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); - if (worldPos.z >= waterLevel) - caustics = float3(1,1,1); - - - + float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif @@ -353,41 +335,14 @@ float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); #if UNDERWATER - // regular fog only if fragment is above water - if (worldPos.z > waterLevel) - #endif + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); + #else shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); + #endif #endif // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); - -#if UNDERWATER - float fogAmount = (cameraPos.z > waterLevel) - ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) - : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); - - float3 eyeVec = normalize(cameraPos.xyz-worldPos); - - float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); - waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; - - float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); - waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; - float3 waterext = float3(0.6, 0.9, 1.0);//water extinction - watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - watercolour = (cameraPos.z <= waterLevel) ? watercolour : watercolour*0.3; - - - float darkness = VISIBILITY*2.0; - darkness = clamp((waterEyePos.z - waterLevel + darkness)/darkness,0.2,1.0); - watercolour *= darkness; - - float isUnderwater = (worldPos.z < waterLevel) ? 1.0 : 0.0; - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); -#endif } #endif diff --git a/files/materials/underwater.h b/files/materials/underwater.h index a760202fa..8474f299d 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -1,4 +1,6 @@ -#define VISIBILITY 1500.0 // how far you can look through water +#define UNDERWATER_COLOUR float3(0.18039, 0.23137, 0.25490) + +#define VISIBILITY 1000.0 // how far you can look through water #define BIG_WAVES_X 0.3 // strength of big waves #define BIG_WAVES_Y 0.3 diff --git a/files/materials/water.mat b/files/materials/water.mat index 372058f0a..3ea6a2c2b 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -56,11 +56,3 @@ material Water } } } - - -material Underwater_Dome -{ - parent openmw_objects_base - - depth_write off -} diff --git a/files/materials/water.shader b/files/materials/water.shader index 59b9e5a43..793cdc95e 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -272,38 +272,16 @@ #if REFRACTION shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; #else - shOutputColour(0).xyz = reflection + specular * sunSpecular.xyz; + shOutputColour(0).xyz = shLerp(reflection, float3(0.18039, 0.23137, 0.25490), (1.0-fresnel)*0.5) + specular * sunSpecular.xyz; #endif // fog - if (isUnderwater == 1) - { - float waterSunGradient = dot(-vVec, -lVec); - waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; - - float waterGradient = dot(-vVec, float3(0.0,-1.0,0.0)); - waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; - float3 waterext = float3(0.6, 0.9, 1.0);//water extinction - watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); - - float darkness = VISIBILITY*2.0; - darkness = clamp((cameraPos.z+darkness)/darkness,0.2,1.0); - - - float fog = shSaturate(length(cameraPos.xyz-position.xyz) / VISIBILITY); - shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, watercolour * darkness, shSaturate(fog / waterext)); - } - else - { - float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); - } + float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); #if REFRACTION shOutputColour(0).w = 1; #else - shOutputColour(0).w = shSaturate(fresnel + specular); + shOutputColour(0).w = shSaturate(fresnel*2 + specular); #endif } diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 00d4eea11..693c5a9cb 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -280,13 +280,6 @@ - - - - - - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 044cc3406..2dee5ac88 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -138,8 +138,6 @@ reflect small statics = false reflect actors = false reflect misc = false -underwater effect = false - [Sound] # Device name. Blank means default device = diff --git a/files/water/underwater_dome.mesh b/files/water/underwater_dome.mesh deleted file mode 100644 index 64ca569c22a04110e7913505c427f0087cef51c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22585 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 From f1d35b73b80c361724efe518de3742f998bd3103 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 3 Mar 2013 19:52:20 +0100 Subject: [PATCH 870/916] Cleanup --- apps/openmw/mwrender/localmap.hpp | 3 --- apps/openmw/mwrender/refraction.cpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 14 -------------- apps/openmw/mwrender/renderingmanager.hpp | 2 -- apps/openmw/mwrender/terrainmaterial.cpp | 6 ------ apps/openmw/mwrender/water.cpp | 17 ++++++++--------- files/materials/objects.shader | 13 ++----------- files/materials/terrain.shader | 7 ++----- files/settings-default.cfg | 6 +++--- 9 files changed, 16 insertions(+), 54 deletions(-) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 9c82258f9..72e637d9a 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -117,9 +117,6 @@ namespace MWRender int mCellX, mCellY; Ogre::AxisAlignedBox mBounds; std::string mInteriorName; - - // maps texture name to according camera settings - std::map mCameraSettings; }; } diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index bb2d88865..d590dbf4c 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -33,7 +33,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Actors + RV_Misc + RV_Statics + RV_StaticsSmall + RV_Terrain + RV_Sky); vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.180, 0.235, 0.22352)); + vp->setBackgroundColour (Ogre::ColourValue(0.18039, 0.23137, 0.25490)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c8b5926d9..382ec6557 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -121,9 +121,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const //mRendering.getScene()->setCameraRelativeRendering(true); // disable unsupported effects - //const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - if (!waterShaderSupported()) - Settings::Manager::setBool("shader", "Water", false); if (!Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("enabled", "Shadows", false); @@ -504,9 +501,6 @@ void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) color.setAsABGR (mCell.mCell->mAmbi.mFog); configureFog(mCell.mCell->mAmbi.mFogDensity, color); - - //if (mWater) - // mWater->setViewportBackground (Ogre::ColourValue(0.8f, 0.9f, 1.0f)); } void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) @@ -854,14 +848,6 @@ void RenderingManager::windowClosed(Ogre::RenderWindow* rw) Ogre::Root::getSingleton ().queueEndRendering (); } -bool RenderingManager::waterShaderSupported() -{ - //const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - //if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) - //return false; - return true; -} - void RenderingManager::applyCompositors() { } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 49cde25a3..e40672ada 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -184,8 +184,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList Ogre::Viewport* getViewport() { return mRendering.getViewport(); } - static bool waterShaderSupported(); - void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); ///< see MWRender::LocalMap::getInteriorMapPosition diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index d5e531f86..8a568883d 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -119,10 +119,6 @@ namespace MWRender shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); } - // caustics - sh::MaterialInstanceTextureUnit* caustics = p->createTextureUnit ("causticMap"); - caustics->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue("water_nm.png"))); - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty(new sh::StringValue( Ogre::StringConverter::toString(numBlendTextures + numLayers + 2)))); @@ -156,8 +152,6 @@ namespace MWRender // shadow --freeTextureUnits; - --freeTextureUnits; // caustics - // each layer needs 1.25 units (1xdiffusespec, 0.25xblend) return static_cast(freeTextureUnits / (1.25f)); } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 49836535f..2801e6494 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -210,6 +210,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mWater = mSceneMgr->createEntity("water"); mWater->setVisibilityFlags(RV_Water); mWater->setCastShadows(false); + mWater->setRenderQueueGroup(RQG_Alpha); mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); @@ -380,6 +381,8 @@ void Water::applyRTT() { delete mReflection; mReflection = NULL; + delete mRefraction; + mRefraction = NULL; // Create rendertarget for reflection //int rttsize = Settings::Manager::getInt("rtt size", "Water"); @@ -389,16 +392,12 @@ void Water::applyRTT() mReflection = new PlaneReflection(mSceneMgr, mSky); mReflection->setParentCamera (mCamera); mReflection->setHeight(mTop); - } - mWater->setRenderQueueGroup(RQG_Alpha); - delete mRefraction; - mRefraction = NULL; - - if (Settings::Manager::getBool("refraction", "Water")) - { - mRefraction = new Refraction(mCamera); - mRefraction->setHeight(mTop); + if (Settings::Manager::getBool("refraction", "Water")) + { + mRefraction = new Refraction(mCamera); + mRefraction->setHeight(mTop); + } } updateVisible(); diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 37ff17843..7c7a604cc 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -260,13 +260,6 @@ float3 lightDir; float3 diffuse = float3(0,0,0); float d; - -#if HAS_VERTEXCOLOR - // ambient vertex colour tracking, FFP behaviour - //float3 ambient = colourPassthrough.xyz * lightAmbient.xyz; -#else - //float3 ambient = materialAmbient.xyz * lightAmbient.xyz; -#endif // shadows only for the first (directional) light #if SHADOWS @@ -288,8 +281,6 @@ - float3 caustics = float3(1,1,1); - #if (UNDERWATER) || (FOG) float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePositionPassthrough,1)).xyz; #endif @@ -311,10 +302,10 @@ #if @shIterator == 0 #if (SHADOWS || SHADOWS_PSSM) - diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow * caustics; + diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow; #else - diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * caustics; + diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0); #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index af5be42cd..0120629fc 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -230,9 +230,6 @@ #endif - - float3 caustics = float3(1,1,1); - #if UNDERWATER float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif @@ -312,10 +309,10 @@ #if @shIterator == 0 #if (SHADOWS || SHADOWS_PSSM) - diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow * caustics; + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow; #else - diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * caustics; + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0); #endif diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 2dee5ac88..6ff7fb432 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -94,7 +94,7 @@ fps = 0 crosshair = true [Objects] -shaders = false +shaders = true # Max. number of lights that affect objects. Setting to 1 will only reflect sunlight # Note: has no effect when shaders are turned off @@ -127,9 +127,9 @@ fog end factor = 1.0 num lights = 8 [Water] -shader = false +shader = true -refraction = false +refraction = true rtt size = 512 reflect terrain = true From 5e50436a946f7efd9bb1fe281fd0a0ceb7513369 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 3 Mar 2013 14:19:02 -0800 Subject: [PATCH 871/916] Convert some BooleanValues to StringValues --- components/nifogre/ogre_nif_loader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 9652fd605..17cac7345 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -752,10 +752,10 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::BooleanValue(!((alphaFlags>>13)&1)))); + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(!((alphaFlags>>13)&1) ? "on" : "off"))); - instance->setProperty("depth_check", sh::makeProperty(new sh::BooleanValue(depthFlags&1))); - instance->setProperty("depth_write", sh::makeProperty(new sh::BooleanValue((depthFlags>>1)&1))); + instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); // depth_func??? sh::Factory::getInstance()._ensureMaterial(matname, "Default"); From 8e076386994bf6e16deeaeea39a8c753a96489fa Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Mon, 4 Mar 2013 12:21:38 +0100 Subject: [PATCH 872/916] Update the trading offer on "max sale" button click --- apps/openmw/mwgui/tradewindow.cpp | 61 +++++++++++++++---------------- apps/openmw/mwgui/tradewindow.hpp | 4 ++ 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 290310760..e3cf8ea3a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -64,6 +64,7 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); + mMaxSaleButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onMaxSaleButtonClicked); mIncreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onIncreaseButtonPressed); mIncreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &TradeWindow::onBalanceButtonReleased); mDecreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &TradeWindow::onDecreaseButtonPressed); @@ -191,21 +192,7 @@ namespace MWGui } // check if the merchant can afford this - int merchantgold; - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) - { - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mNpdt52.mGold == -10) - merchantgold = ref->mBase->mNpdt12.mGold; - else - merchantgold = ref->mBase->mNpdt52.mGold; - } - else // ESM::Creature - { - MWWorld::LiveCellRef* ref = mPtr.get(); - merchantgold = ref->mBase->mData.mGold; - } - if (mCurrentBalance > 0 && merchantgold < mCurrentBalance) + if (mCurrentBalance > 0 && getMerchantGold() < mCurrentBalance) { // user notification MWBase::Environment::get().getWindowManager()-> @@ -293,6 +280,12 @@ namespace MWGui mWindowManager.removeGuiMode(GM_Barter); } + void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) + { + mCurrentBalance = getMerchantGold(); + updateLabels(); + } + void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { mBalanceButtonsState = BBS_Increase; @@ -341,22 +334,7 @@ namespace MWGui mTotalBalance->setCaption(boost::lexical_cast(-mCurrentBalance)); } - int merchantgold; - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) - { - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mNpdt52.mGold == -10) - merchantgold = ref->mBase->mNpdt12.mGold; - else - merchantgold = ref->mBase->mNpdt52.mGold; - } - else // ESM::Creature - { - MWWorld::LiveCellRef* ref = mPtr.get(); - merchantgold = ref->mBase->mData.mGold; - } - - mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(merchantgold)); + mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(getMerchantGold())); } std::vector TradeWindow::getEquippedItems() @@ -468,4 +446,25 @@ namespace MWGui mWindowManager.removeGuiMode(GM_Barter); mWindowManager.removeGuiMode(GM_Dialogue); } + + int TradeWindow::getMerchantGold() + { + int merchantGold; + + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + MWWorld::LiveCellRef* ref = mPtr.get(); + if (ref->mBase->mNpdt52.mGold == -10) + merchantGold = ref->mBase->mNpdt12.mGold; + else + merchantGold = ref->mBase->mNpdt52.mGold; + } + else // ESM::Creature + { + MWWorld::LiveCellRef* ref = mPtr.get(); + merchantGold = ref->mBase->mData.mGold; + } + + return merchantGold; + } } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index c1d31917b..ea749f5a2 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -74,6 +74,7 @@ namespace MWGui void onFilterChanged(MyGUI::Widget* _sender); void onOfferButtonClicked(MyGUI::Widget* _sender); void onCancelButtonClicked(MyGUI::Widget* _sender); + void onMaxSaleButtonClicked(MyGUI::Widget* _sender); void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); @@ -93,6 +94,9 @@ namespace MWGui void updateLabels(); virtual void onReferenceUnavailable(); + + private: + int getMerchantGold(); }; } From 215d45aaf7e83fdc1cd1b9957a3c0e53ac80c57a Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Mon, 4 Mar 2013 12:17:48 +0100 Subject: [PATCH 873/916] Make trade window's "max sale" button clickable The HBox widget above it was stealing the input events. --- files/mygui/openmw_trade_window.layout | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index d38377f98..ecc794c92 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -51,10 +51,6 @@ - - - - @@ -66,6 +62,10 @@ + + + + From 48b3f1e0cf1e118480d795bf797d0c4fbacc8e2b Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 4 Mar 2013 12:08:35 +0000 Subject: [PATCH 874/916] Clean up. But still a little hacky --- apps/openmw/mwworld/physicssystem.cpp | 6 ++---- libs/openengine/bullet/physic.cpp | 4 ++++ libs/openengine/bullet/physic.hpp | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 90c090f59..316e57b78 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -110,7 +110,7 @@ namespace MWWorld float remainingTime = time; bool isInterior = !ptr.getCell()->isExterior(); Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); - physicActor->mBody->translate(btVector3(0,0,1000)); + physicActor->enableCollisions(false); Ogre::Vector3 velocity; if(!gravity) @@ -147,7 +147,6 @@ namespace MWWorld // trace to where character would go if there were no obstructions newtrace(&trace, newPosition, newPosition+clippedVelocity*remainingTime, halfExtents, isInterior, engine); newPosition = trace.endpos; - //std::cout << newPosition.x << " "; remainingTime = remainingTime * (1.0f-trace.fraction); // check for obstructions @@ -191,8 +190,7 @@ namespace MWWorld } physicActor->setOnGround(onground); physicActor->setVerticalForce(!onground ? clippedVelocity.z - time*627.2f : 0.0f); - physicActor->mBody->translate(btVector3(0,0,-1000)); - //std::cout << position.x << " " << newPosition.x << " " << position.y << " " << newPosition.y << std::endl; + physicActor->enableCollisions(true); return newPosition; } }; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index f993ce68e..677d75f33 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -37,6 +37,8 @@ namespace Physic Ogre::Quaternion inverse = mBoxRotation.Inverse(); mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map + //mBody->setCollisionFlags(COL_NOTHING); + //mBody->setMas } PhysicActor::~PhysicActor() @@ -50,6 +52,8 @@ namespace Physic void PhysicActor::enableCollisions(bool collision) { + if(collision && !collisionMode) mBody->translate(btVector3(0,0,-1000)); + if(!collision && collisionMode) mBody->translate(btVector3(0,0,1000)); collisionMode = collision; } diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 6a7150fca..e579e3546 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -129,10 +129,10 @@ namespace Physic void operator delete (void * Data) { _aligned_free (Data); } #endif - OEngine::Physic::RigidBody* mBody; private: - + + OEngine::Physic::RigidBody* mBody; Ogre::Vector3 mBoxScaledTranslation; btQuaternion mBoxRotationInverse; Ogre::Quaternion mBoxRotation; From 3384d92761a921562b7ec0b15444007ef11fd18e Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 4 Mar 2013 12:28:43 +0000 Subject: [PATCH 875/916] oups introduced a bug.. --- apps/openmw/mwscript/transformationextensions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8222ef150..d86a6e348 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -119,15 +119,15 @@ namespace MWScript if (axis == "x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()); } else if (axis == "y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()); } else if (axis == "z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); From 65081f5520b733b235b87a9b98e5f6afbb331962 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Mar 2013 13:59:06 +0100 Subject: [PATCH 876/916] added variant class --- apps/opencs/view/world/vartypedelegate.hpp | 2 + components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 12 - components/esm/loadglob.hpp | 1 + components/esm/loadgmst.hpp | 1 + components/esm/loadinfo.hpp | 1 + components/esm/variant.cpp | 256 ++++++++++++++++++++ components/esm/variant.hpp | 85 +++++++ components/esm/variantimp.cpp | 262 +++++++++++++++++++++ components/esm/variantimp.hpp | 179 ++++++++++++++ 10 files changed, 788 insertions(+), 13 deletions(-) create mode 100644 components/esm/variant.cpp create mode 100644 components/esm/variant.hpp create mode 100644 components/esm/variantimp.cpp create mode 100644 components/esm/variantimp.hpp diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp index 621dd316b..c8493f029 100644 --- a/apps/opencs/view/world/vartypedelegate.hpp +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_VARTYPEDELEGATE_H #define CSV_WORLD_VARTYPEDELEGATE_H +#include + #include "enumdelegate.hpp" namespace CSVWorld diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00342e2ac..0c75123cb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (esm loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat - loadweap records aipackage effectlist spelllist + loadweap records aipackage effectlist spelllist variant variantimp ) add_component_dir (misc diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 143d90034..bd86f9ba0 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -9,18 +9,6 @@ namespace ESM // Pixel color value. Standard four-byte rr,gg,bb,aa format. typedef int32_t Color; -enum VarType -{ - VT_Unknown, - VT_None, - VT_Short, // stored as a float, kinda - VT_Int, - VT_Long, // stored as a float - VT_Float, - VT_String, - VT_Ignored -}; - enum Specialization { SPC_Combat = 0, diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 6111648a6..96d2fcaf4 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -4,6 +4,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index f7aec5c76..12f212081 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -4,6 +4,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index f1decb9c6..ca08c3b55 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -5,6 +5,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp new file mode 100644 index 000000000..bf8d2069b --- /dev/null +++ b/components/esm/variant.cpp @@ -0,0 +1,256 @@ +#include "variant.hpp" + +#include +#include + +#include "esmreader.hpp" +#include "variantimp.hpp" + +ESM::Variant::Variant() : mType (VT_None), mData (0) {} + +ESM::Variant::~Variant() +{ + delete mData; +} + +ESM::Variant& ESM::Variant::operator= (const Variant& variant) +{ + if (&variant!=this) + { + VariantDataBase *newData = variant.mData ? variant.mData->clone() : 0; + + delete mData; + + mType = variant.mType; + mData = newData; + } + + return *this; +} + +ESM::Variant::Variant (const Variant& variant) +: mType (variant.mType), mData (variant.mData ? variant.mData->clone() : 0) +{} + +ESM::VarType ESM::Variant::getType() const +{ + return mType; +} + +std::string ESM::Variant::toString() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to string"); + + return mData->getString(); +} + +int ESM::Variant::getInteger() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to integer"); + + return mData->getInteger(); +} + +float ESM::Variant::getFloat() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to float"); + + return mData->getFloat(); +} + +void ESM::Variant::read (ESMReader& esm, Format format) +{ + // type + VarType type = VT_Unknown; + + if (format==Format_Global) + { + std::string typeId = esm.getHNString ("FNAM"); + + if (typeId == "s") + type = VT_Short; + else if (typeId == "l") + type = VT_Long; + else if (typeId == "f") + type = VT_Float; + else + esm.fail ("illegal global variable type " + typeId); + } + else // GMST + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="STRV") + { + type = VT_String; + } + else if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } + + setType (type); + + // data + if (mData) + mData->read (esm, format, mType); +} + +void ESM::Variant::write (ESMWriter& esm, Format format) const +{ + if (mType==VT_Unknown) + { + throw std::runtime_error ("can not serialise variant of unknown type"); + } + else if (mType==VT_None) + { + if (format==Format_Global) + throw std::runtime_error ("can not serialise variant of type none to global format"); + + // nothing to do here for GMST format + } + else + mData->write (esm, format, mType); +} + +void ESM::Variant::write (std::ostream& stream) const +{ + switch (mType) + { + case VT_Unknown: + + stream << "variant unknown"; + break; + + case VT_None: + + stream << "variant none"; + break; + + case VT_Short: + + stream << "variant short: " << mData->getInteger(); + break; + + case VT_Int: + + stream << "variant int: " << mData->getInteger(); + break; + + case VT_Long: + + stream << "variant long: " << mData->getInteger(); + break; + + case VT_Float: + + stream << "variant float: " << mData->getFloat(); + break; + + case VT_String: + + stream << "variant string: \"" << mData->getString() << "\2"; + break; + } +} + +void ESM::Variant::setType (VarType type) +{ + if (type!=mType) + { + VariantDataBase *newData = 0; + + switch (type) + { + case VT_Unknown: + case VT_None: + + break; // no data + + case VT_Short: + case VT_Int: + case VT_Long: + + newData = new VariantIntegerData (mData); + break; + + case VT_Float: + + newData = new VariantFloatData (mData); + break; + + case VT_String: + + newData = new VariantStringData (mData); + break; + } + + delete mData; + mData = newData; + mType = type; + } +} + +void ESM::Variant::setString (const std::string& value) +{ + if (!mData) + throw std::runtime_error ("can not assign string to empty variant"); + + mData->setString (value); +} + +void ESM::Variant::setInteger (int value) +{ + if (!mData) + throw std::runtime_error ("can not assign integer to empty variant"); + + mData->setInteger (value); +} + +void ESM::Variant::setFloat (float value) +{ + if (!mData) + throw std::runtime_error ("can not assign float to empty variant"); + + mData->setFloat (value); +} + +bool ESM::Variant::isEqual (const Variant& value) const +{ + if (mType!=value.mType) + return false; + + if (!mData) + return true; + + assert (value.mData); + + return mData->isEqual (*value.mData); +} + +std::ostream& ESM::operator<< (std::ostream& stream, const Variant& value) +{ + value.write (stream); + return stream; +} + +bool ESM::operator== (const Variant& left, const Variant& right) +{ + return left.isEqual (right); +} + +bool ESM::operator!= (const Variant& left, const Variant& right) +{ + return !(left==right); +} \ No newline at end of file diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp new file mode 100644 index 000000000..b50bb1d2f --- /dev/null +++ b/components/esm/variant.hpp @@ -0,0 +1,85 @@ +#ifndef OPENMW_ESM_VARIANT_H +#define OPENMW_ESM_VARIANT_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + enum VarType + { + VT_Unknown, + VT_None, + VT_Short, // stored as a float, kinda + VT_Int, + VT_Long, // stored as a float + VT_Float, + VT_String + }; + + class VariantDataBase; + + class Variant + { + VarType mType; + VariantDataBase *mData; + + public: + + enum Format + { + Format_Global, + Format_Gmst + }; + + Variant(); + + ~Variant(); + + Variant& operator= (const Variant& variant); + + Variant (const Variant& variant); + + VarType getType() const; + + std::string toString() const; + ///< Will throw an exception, if value can not be represented as a string. + + int getInteger() const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + + float getFloat() const; + ///< Will throw an exception, if value can not be represented as a float value. + + void read (ESMReader& esm, Format format); + + void write (ESMWriter& esm, Format format) const; + + void write (std::ostream& stream) const; + ///< Write in text format. + + void setType (VarType type); + + void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + + void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + bool isEqual (const Variant& value) const; + }; + + std::ostream& operator<<(std::ostream& stream, const Variant& value); + + bool operator== (const Variant& left, const Variant& right); + bool operator!= (const Variant& left, const Variant& right); +} + +#endif \ No newline at end of file diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp new file mode 100644 index 000000000..e99cc50b5 --- /dev/null +++ b/components/esm/variantimp.cpp @@ -0,0 +1,262 @@ + +#include "variantimp.hpp" + +#include + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +ESM::VariantDataBase::~VariantDataBase() {} + +std::string ESM::VariantDataBase::getString (bool default_) const +{ + if (default_) + return ""; + + throw std::runtime_error ("can not convert variant to string"); +} + +int ESM::VariantDataBase::getInteger (bool default_) const +{ + if (default_) + return 0; + + throw std::runtime_error ("can not convert variant to integer"); +} + +float ESM::VariantDataBase::getFloat (bool default_) const +{ + if (default_) + return 0; + + throw std::runtime_error ("can not convert variant to float"); +} + +void ESM::VariantDataBase::setString (const std::string& value) +{ + throw std::runtime_error ("conversion of string to variant not possible"); +} + +void ESM::VariantDataBase::setInteger (int value) +{ + throw std::runtime_error ("conversion of integer to variant not possible"); +} + +void ESM::VariantDataBase::setFloat (float value) +{ + throw std::runtime_error ("conversion of float to variant not possible"); +} + + + +ESM::VariantStringData::VariantStringData (const VariantDataBase *data) +{ + if (data) + mValue = data->getString (true); +} + +ESM::VariantDataBase *ESM::VariantStringData::clone() const +{ + return new VariantStringData (*this); +} + +std::string ESM::VariantStringData::getString (bool default_) const +{ + return mValue; +} + +void ESM::VariantStringData::setString (const std::string& value) +{ + mValue = value; +} + +void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_String) + throw std::logic_error ("not a string type"); + + if (format==Variant::Format_Global) + esm.fail ("global variables of type string not supported"); + + // GMST + mValue = esm.getHString(); +} + +void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_String) + throw std::logic_error ("not a string type"); + + if (format==Variant::Format_Global) + throw std::runtime_error ("global variables of type string not supported"); + + // GMST + esm.writeHNString ("STRV", mValue); +} + +bool ESM::VariantStringData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} + + + +ESM::VariantIntegerData::VariantIntegerData (const VariantDataBase *data) : mValue (0) +{ + if (data) + mValue = data->getInteger (true); +} + +ESM::VariantDataBase *ESM::VariantIntegerData::clone() const +{ + return new VariantIntegerData (*this); +} + +int ESM::VariantIntegerData::getInteger (bool default_) const +{ + return mValue; +} + +float ESM::VariantIntegerData::getFloat (bool default_) const +{ + return mValue; +} + +void ESM::VariantIntegerData::setInteger (int value) +{ + mValue = value; +} + +void ESM::VariantIntegerData::setFloat (float value) +{ + mValue = static_cast (value); +} + +void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_Short && type!=VT_Long && type!=VT_Int) + throw std::logic_error ("not an integer type"); + + if (format==Variant::Format_Global) + { + float value; + esm.getHNT (value, "FLTV"); + + if (type==VT_Short) + { + if (value!=value) + mValue = 0; // nan + else + mValue = static_cast (value); + } + else if (type==VT_Long) + mValue = static_cast (value); + else + esm.fail ("unsupported global variable integer type"); + } + else // GMST + { + if (type==VT_Int) + esm.fail ("unsupported global variable integer type"); + + esm.getHT (mValue); + } +} + +void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_Short && type!=VT_Long && type!=VT_Int) + throw std::logic_error ("not an integer type"); + + if (format==Variant::Format_Global) + { + if (type==VT_Short || type==VT_Long) + { + float value = mValue; + esm.writeHNString ("FNAM", type==VT_Short ? "s" : "l"); + esm.writeHNT ("FLTV", value); + } + else + throw std::runtime_error ("unsupported global variable integer type"); + } + else // GMST + { + if (type==VT_Int) + throw std::runtime_error ("unsupported global variable integer type"); + + esm.writeHNT ("INTV", mValue); + } +} + +bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} + + +ESM::VariantFloatData::VariantFloatData (const VariantDataBase *data) : mValue (0) +{ + if (data) + mValue = data->getFloat (true); +} + +ESM::VariantDataBase *ESM::VariantFloatData::clone() const +{ + return new VariantFloatData (*this); +} + +int ESM::VariantFloatData::getInteger (bool default_) const +{ + return static_cast (mValue); +} + +float ESM::VariantFloatData::getFloat (bool default_) const +{ + return mValue; +} + +void ESM::VariantFloatData::setInteger (int value) +{ + mValue = value; +} + +void ESM::VariantFloatData::setFloat (float value) +{ + mValue = value; +} + +void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_Float) + throw std::logic_error ("not a float type"); + + if (format==Variant::Format_Global) + { + esm.getHNT (mValue, "FLTV"); + } + else // GMST + { + esm.getHT (mValue); + } +} + +void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_Float) + throw std::logic_error ("not a float type"); + + if (format==Variant::Format_Global) + { + esm.writeHNString ("FNAM", "f"); + esm.writeHNT ("FLTV", mValue); + } + else // GMST + { + esm.writeHNT ("INTV", mValue); + } +} + +bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} \ No newline at end of file diff --git a/components/esm/variantimp.hpp b/components/esm/variantimp.hpp new file mode 100644 index 000000000..1dc20c21f --- /dev/null +++ b/components/esm/variantimp.hpp @@ -0,0 +1,179 @@ +#ifndef OPENMW_ESM_VARIANTIMP_H +#define OPENMW_ESM_VARIANTIMP_H + +#include + +#include "variant.hpp" + +namespace ESM +{ + class VariantDataBase + { + public: + + virtual ~VariantDataBase(); + + virtual VariantDataBase *clone() const = 0; + + virtual std::string getString (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a string. + /// + /// \note Numeric values are not converted to strings. + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + /// + /// Default-implementation: throw an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + /// + /// Default-implementation: throw an exception. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + /// + /// Default-implementation: throw an exception. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type) = 0; + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const = 0; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const = 0; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + + }; + + class VariantStringData : public VariantDataBase + { + std::string mValue; + + public: + + VariantStringData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual std::string getString (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a string. + /// + /// \note Numeric values are not converted to strings. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; + + class VariantIntegerData : public VariantDataBase + { + int mValue; + + public: + + VariantIntegerData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; + + class VariantFloatData : public VariantDataBase + { + float mValue; + + public: + + VariantFloatData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; +} + +#endif From a1ac20c6f398ef38ff2797a6ab0ba6ed264c0e2e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Mar 2013 14:32:59 +0100 Subject: [PATCH 877/916] changed global variable records to new variant type --- apps/esmtool/record.cpp | 4 +-- apps/opencs/model/doc/document.cpp | 12 ++++--- apps/opencs/model/world/columns.hpp | 4 +-- apps/openmw/mwworld/globals.cpp | 11 +++---- components/esm/loadglob.cpp | 49 ++++------------------------- components/esm/loadglob.hpp | 4 +-- 6 files changed, 22 insertions(+), 62 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a732f1938..929201417 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -713,9 +713,7 @@ void Record::print() template<> void Record::print() { - // nothing to print (well, nothing that's correct anyway) - std::cout << " Type: " << mData.mType << std::endl; - std::cout << " Value: " << mData.mValue << std::endl; + std::cout << " " << mData.mValue << std::endl; } template<> diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index b361577be..f6df1f499 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -154,8 +154,7 @@ void CSMDoc::Document::addOptionalGlobals() { ESM::Global global; global.mId = sGlobals[i]; - global.mType = ESM::VT_Int; - global.mValue = 0; + global.mValue.setType (ESM::VT_Int); addOptionalGlobal (global); } } @@ -192,9 +191,14 @@ void CSMDoc::Document::createBase() for (int i=0; sGlobals[i]; ++i) { ESM::Global record; + record.mId = sGlobals[i]; - record.mValue = i==0 ? 1 : 0; - record.mType = ESM::VT_Float; + + record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Int); + + if (i==0) + record.mValue.setInteger (1); + getData().getGlobals().add (record); } } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2d81a24e9..8855edc46 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -12,13 +12,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mValue; + return record.get().mValue.getFloat(); } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mValue = data.toFloat(); + record2.mValue.setFloat (data.toFloat()); record.setModified (record2); } diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 8742dd892..9e57910ee 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -47,27 +47,24 @@ namespace MWWorld char type = ' '; Data value; - switch (iter->mType) + switch (iter->mValue.getType()) { case ESM::VT_Short: type = 's'; - value.mShort = *reinterpret_cast ( - &iter->mValue); + value.mShort = iter->mValue.getInteger(); break; case ESM::VT_Long: type = 'l'; - value.mLong = *reinterpret_cast ( - &iter->mValue); + value.mLong = iter->mValue.getInteger(); break; case ESM::VT_Float: type = 'f'; - value.mFloat = *reinterpret_cast ( - &iter->mValue); + value.mFloat = iter->mValue.getFloat(); break; default: diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 9e20578ce..0cb6d0a41 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -6,60 +6,23 @@ namespace ESM { -void Global::load(ESMReader &esm) -{ - std::string tmp = esm.getHNString("FNAM"); - if (tmp == "s") - mType = VT_Short; - else if (tmp == "l") - mType = VT_Long; - else if (tmp == "f") - mType = VT_Float; - else - esm.fail("Illegal global variable type " + tmp); - - // Note: Both floats and longs are represented as floats. - esm.getHNT(mValue, "FLTV"); - - if (mType==VT_Short) + void Global::load(ESMReader &esm) { - if (mValue!=mValue) - mValue = 0; // nan - else - mValue = static_cast (mValue); + mValue.read (esm, ESM::Variant::Format_Global); } -} -void Global::save(ESMWriter &esm) -{ - switch(mType) + void Global::save(ESMWriter &esm) { - case VT_Short: - esm.writeHNString("FNAM", "s"); - break; - - case VT_Long: - esm.writeHNString("FNAM", "l"); - break; - - case VT_Float: - esm.writeHNString("FNAM", "f"); - break; - - default: - return; + mValue.write (esm, ESM::Variant::Format_Global); } - esm.writeHNT("FLTV", mValue); -} void Global::blank() { - mValue = 0; - mType = VT_Float; + mValue.setType (ESM::VT_None); } bool operator== (const Global& left, const Global& right) { - return left.mId==right.mId && left.mValue==right.mValue && left.mType==right.mType; + return left.mId==right.mId && left.mValue==right.mValue; } } diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 96d2fcaf4..72e16c0ce 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -3,7 +3,6 @@ #include -#include "defs.hpp" #include "variant.hpp" namespace ESM @@ -19,8 +18,7 @@ class ESMWriter; struct Global { std::string mId; - float mValue; - VarType mType; + Variant mValue; void load(ESMReader &esm); void save(ESMWriter &esm); From cab5315a8e6ff5c785930787051e14084db5cc20 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Mar 2013 16:28:20 +0100 Subject: [PATCH 878/916] Disable mipmaps generation --- apps/openmw/mwrender/renderingmanager.cpp | 3 ++- files/settings-default.cfg | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 382ec6557..3f559c9fd 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -100,7 +100,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mFactory->loadAllFiles(); // Set default mipmap level (NB some APIs ignore this) - TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); + // Mipmap generation is currently disabled because it causes issues on Intel/AMD + //TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); // Set default texture filtering options TextureFilterOptions tfo; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 6ff7fb432..69aa20883 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -52,7 +52,8 @@ texture filtering = anisotropic anisotropy = 4 # Number of texture mipmaps to generate -num mipmaps = 5 +# This setting is currently ignored due to mipmap generation problems on Intel/AMD +#num mipmaps = 5 shader mode = From ca707aa65f6d16126cb33f63f6096691af61531a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Mar 2013 16:57:00 +0100 Subject: [PATCH 879/916] Transparency should be evaluated per subentity, not per NIF --- apps/openmw/mwrender/activatoranimation.cpp | 19 +++-------- apps/openmw/mwrender/creatureanimation.cpp | 18 ++--------- apps/openmw/mwrender/npcanimation.cpp | 36 ++++----------------- apps/openmw/mwrender/objects.cpp | 30 +++++++---------- 4 files changed, 24 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 0dc16ecb6..961c07003 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -30,24 +30,13 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) { Ogre::Entity *ent = mEntityList.mEntities[i]; - bool transparent = false; - for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) + for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { - Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + Ogre::SubEntity* subEnt = ent->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } + ent->setVisibilityFlags(RV_Misc); - ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } setAnimationSource(mesh); } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 73bb80547..22f84ee01 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -31,23 +31,11 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) Ogre::Entity *ent = mEntityList.mEntities[i]; ent->setVisibilityFlags(RV_Actors); - bool transparent = false; - for(unsigned int j=0;!transparent && j < ent->getNumSubEntities(); ++j) + for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { - Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + Ogre::SubEntity* subEnt = ent->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } - ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } std::vector names; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 33addd284..a7d5c22af 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -107,23 +107,11 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor if (mVisibilityFlags != 0) base->setVisibilityFlags(mVisibilityFlags); - bool transparent = false; - for(unsigned int j=0;!transparent && j < base->getNumSubEntities();++j) + for(unsigned int j=0; j < base->getNumSubEntities(); ++j) { - Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + Ogre::SubEntity* subEnt = base->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } - base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } std::vector skelnames(1, smodel); @@ -326,23 +314,11 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int if (mVisibilityFlags != 0) parts[i]->setVisibilityFlags(mVisibilityFlags); - bool transparent = false; - for(unsigned int j=0;!transparent && j < parts[i]->getNumSubEntities();++j) + for(unsigned int j=0; j < parts[i]->getNumSubEntities(); ++j) { - Ogre::MaterialPtr mat = parts[i]->getSubEntity(j)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + Ogre::SubEntity* subEnt = parts[i]->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } - parts[i]->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } if(entities.mSkelBase) { diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 525dcdcc4..cb1dfa75b 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -129,36 +129,28 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()].merge(bounds); - bool transparent = false; - for(size_t i = 0;!transparent && i < entities.mEntities.size();i++) + bool anyTransparency = false; + for(size_t i = 0;!anyTransparency && i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; - for(unsigned int i=0;!transparent && i < ent->getNumSubEntities(); ++i) + for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i) { - Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while(!transparent && techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while(!transparent && passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); - transparent = pass->isTransparent(); - } - } + anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent(); } } - if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) + if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || anyTransparency) { for(size_t i = 0;i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; - + for(unsigned int i=0; i < ent->getNumSubEntities(); ++i) + { + Ogre::SubEntity* subEnt = ent->getSubEntity(i); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); + } ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); - ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } } else @@ -203,7 +195,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool sg->setCastShadows(true); - sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + sg->setRenderQueueGroup(RQG_Main); std::vector::reverse_iterator iter = entities.mEntities.rbegin(); while(iter != entities.mEntities.rend()) From d5c6c221c102699e548256721aa6ac4d06f9dae9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Mar 2013 17:28:01 +0100 Subject: [PATCH 880/916] Books/scrolls: Fix the take button incorrectly showing --- apps/openmw/mwgui/inventorywindow.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 40771af16..4a0234644 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -160,11 +160,8 @@ namespace MWGui // the "Take" button should not be visible. // NOTE: the take button is "reset" when the window opens, so we can safely do the following // without screwing up future book windows - if (mDragAndDrop->mDraggedFrom == this) - { - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); - } + mWindowManager.getBookWindow()->setTakeButtonShow(false); + mWindowManager.getScrollWindow()->setTakeButtonShow(false); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); From 9f0bd95ef1122883e1e8e5e9542c9d93ba9ed7f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 4 Mar 2013 17:57:35 +0100 Subject: [PATCH 881/916] Added BM trees to transparency overrides --- files/transparency-overrides.cfg | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/files/transparency-overrides.cfg b/files/transparency-overrides.cfg index 299792be1..65f9b477a 100644 --- a/files/transparency-overrides.cfg +++ b/files/transparency-overrides.cfg @@ -572,3 +572,52 @@ [textures\tx_velothi_glyph00.dds] alphaRejectValue = 128 + + + +# Bloodmoon + +[textures\tx_bm_holly_01.dds] + alphaRejectValue = 128 + +[textures\tx_bm_holly_snow_01.dds] + alphaRejectValue = 128 + +[textures\tx_bm_pine_04a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_pine_03a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_pine_02a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_pine_01a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_shrub_02.dds] + alphaRejectValue = 128 + +[textures\tx_bm_shrub_01.dds] + alphaRejectValue = 128 + +[textures\tx_bm_snow_pine_01a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_snow_pine_02a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_snow_pine_03a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_snow_pine_04a.dds] + alphaRejectValue = 128 + +[textures\tx_bm_deadpine_01.dds] + alphaRejectValue = 128 + +[textures\tx_bm_shrub_snow_02.dds] + alphaRejectValue = 128 + +[textures\tx_bm_s_deadpine_01.dds] + alphaRejectValue = 128 From 2f14f26b96cbe5c0cf79c9a35840bcde862a9966 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 4 Mar 2013 10:35:13 -0800 Subject: [PATCH 882/916] Use the full unique mesh name for the material instead of the NIF name --- components/nifogre/ogrenifloader.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 44a8e48cd..6f7afee43 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -993,7 +993,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - std::string matname = NIFMaterialLoader::getMaterial(shape, mName, mGroup, + std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop); if(matname.length() > 0) @@ -1001,12 +1001,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, - const Nif::NiTexturingProperty *texprop=NULL, - const Nif::NiMaterialProperty *matprop=NULL, - const Nif::NiAlphaProperty *alphaprop=NULL, - const Nif::NiVertexColorProperty *vertprop=NULL, - const Nif::NiZBufferProperty *zprop=NULL, - const Nif::NiSpecularProperty *specprop=NULL) + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop) { // Scan the property list for material information const Nif::PropertyList &proplist = node->props; @@ -1081,7 +1081,7 @@ public: } const Nif::Node *node = dynamic_cast(nif->getRecord(0)); - findTriShape(mesh, node); + findTriShape(mesh, node, NULL, NULL, NULL, NULL, NULL, NULL); } void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) From fb5213a754cab17c457c649bdb089f96ed519424 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 5 Mar 2013 02:17:28 +0100 Subject: [PATCH 883/916] Made the GraphicsPage use a .ui file and added support for custom res --- apps/launcher/graphicspage.cpp | 137 ++++++++++++++++--------------- apps/launcher/graphicspage.hpp | 21 ++--- apps/launcher/ui/graphicspage.ui | 22 +++-- 3 files changed, 92 insertions(+), 88 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 741aacc9d..590504354 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -30,48 +30,17 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &g , mGraphicsSettings(graphicsSetting) , QWidget(parent) { - QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this); + setupUi(this); - QLabel *rendererLabel = new QLabel(tr("Rendering Subsystem:"), rendererGroup); - mRendererComboBox = new QComboBox(rendererGroup); + // Set the maximum res we can set in windowed mode + QRect res = QApplication::desktop()->screenGeometry(); + customWidthSpinBox->setMaximum(res.width()); + customHeightSpinBox->setMaximum(res.height()); - // Layout for the combobox and label - QGridLayout *renderSystemLayout = new QGridLayout(); - renderSystemLayout->addWidget(rendererLabel, 0, 0, 1, 1); - renderSystemLayout->addWidget(mRendererComboBox, 0, 1, 1, 1); + 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))); - // Display - QGroupBox *displayGroup = new QGroupBox(tr("Display"), this); - - mVSyncCheckBox = new QCheckBox(tr("Vertical Sync"), displayGroup); - mFullScreenCheckBox = new QCheckBox(tr("Full Screen"), displayGroup); - - QLabel *antiAliasingLabel = new QLabel(tr("Antialiasing:"), displayGroup); - QLabel *resolutionLabel = new QLabel(tr("Resolution:"), displayGroup); - - mResolutionComboBox = new QComboBox(displayGroup); - mAntiAliasingComboBox = new QComboBox(displayGroup); - - QVBoxLayout *rendererGroupLayout = new QVBoxLayout(rendererGroup); - rendererGroupLayout->addLayout(renderSystemLayout); - - QGridLayout *displayGroupLayout = new QGridLayout(displayGroup); - displayGroupLayout->addWidget(mVSyncCheckBox, 0, 0, 1, 1); - displayGroupLayout->addWidget(mFullScreenCheckBox, 1, 0, 1, 1); - displayGroupLayout->addWidget(antiAliasingLabel, 2, 0, 1, 1); - displayGroupLayout->addWidget(mAntiAliasingComboBox, 2, 1, 1, 1); - displayGroupLayout->addWidget(resolutionLabel, 3, 0, 1, 1); - displayGroupLayout->addWidget(mResolutionComboBox, 3, 1, 1, 1); - - // Layout for the whole page - QVBoxLayout *pageLayout = new QVBoxLayout(this); - QSpacerItem *vSpacer1 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding); - - pageLayout->addWidget(rendererGroup); - pageLayout->addWidget(displayGroup); - pageLayout->addItem(vSpacer1); - - connect(mRendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&))); } bool GraphicsPage::setupOgre() @@ -138,7 +107,7 @@ bool GraphicsPage::setupOgre() for (Ogre::RenderSystemList::const_iterator r = renderers.begin(); r != renderers.end(); ++r) { mSelectedRenderSystem = *r; - mRendererComboBox->addItem((*r)->getName().c_str()); + rendererComboBox->addItem((*r)->getName().c_str()); } QString openGLName = QString("OpenGL Rendering Subsystem"); @@ -160,21 +129,21 @@ bool GraphicsPage::setupOgre() } // Now fill the GUI elements - int index = mRendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system"))); + int index = rendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system"))); if ( index != -1) { - mRendererComboBox->setCurrentIndex(index); + rendererComboBox->setCurrentIndex(index); } else { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(direct3DName)); + rendererComboBox->setCurrentIndex(rendererComboBox->findText(direct3DName)); #else - mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(openGLName)); + rendererComboBox->setCurrentIndex(rendererComboBox->findText(openGLName)); #endif } - mAntiAliasingComboBox->clear(); - mResolutionComboBox->clear(); - mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); + antiAliasingComboBox->clear(); + resolutionComboBox->clear(); + antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); + resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); // Load the rest of the values loadSettings(); @@ -184,38 +153,46 @@ bool GraphicsPage::setupOgre() void GraphicsPage::loadSettings() { if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) - mVSyncCheckBox->setCheckState(Qt::Checked); + vSyncCheckBox->setCheckState(Qt::Checked); if (mGraphicsSettings.value(QString("Video/fullscreen")) == QLatin1String("true")) - mFullScreenCheckBox->setCheckState(Qt::Checked); + fullScreenCheckBox->setCheckState(Qt::Checked); - int aaIndex = mAntiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); + int aaIndex = antiAliasingComboBox->findText(mGraphicsSettings.value(QString("Video/antialiasing"))); if (aaIndex != -1) - mAntiAliasingComboBox->setCurrentIndex(aaIndex); + antiAliasingComboBox->setCurrentIndex(aaIndex); - QString resolution = mGraphicsSettings.value(QString("Video/resolution x")); - resolution.append(QString(" x ") + mGraphicsSettings.value(QString("Video/resolution y"))); + QString width = mGraphicsSettings.value(QString("Video/resolution x")); + QString height = mGraphicsSettings.value(QString("Video/resolution y")); + QString resolution = width + QString(" x ") + height; - int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); + int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith); - if (resIndex != -1) - mResolutionComboBox->setCurrentIndex(resIndex); + if (resIndex != -1) { + standardRadioButton->toggle(); + resolutionComboBox->setCurrentIndex(resIndex); + } else { + customRadioButton->toggle(); + customWidthSpinBox->setValue(width.toInt()); + customHeightSpinBox->setValue(height.toInt()); + + } } void GraphicsPage::saveSettings() { - mVSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true")) + vSyncCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/vsync"), QString("true")) : mGraphicsSettings.setValue(QString("Video/vsync"), QString("false")); - mFullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) + fullScreenCheckBox->checkState() ? mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("true")) : mGraphicsSettings.setValue(QString("Video/fullscreen"), QString("false")); - mGraphicsSettings.setValue(QString("Video/antialiasing"), mAntiAliasingComboBox->currentText()); - mGraphicsSettings.setValue(QString("Video/render system"), mRendererComboBox->currentText()); + mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); + mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText()); QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); - if (resolutionRe.exactMatch(mResolutionComboBox->currentText().simplified())) { + if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); } @@ -277,6 +254,7 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) // remove extra tokens after the resolution (for example bpp, can be there or not depending on rendersystem) QStringList tokens = qval.split(" ", QString::SkipEmptyParts); assert (tokens.size() >= 3); + QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2); QString aspect = getAspect(tokens.at(0).toInt(),tokens.at(2).toInt()); @@ -304,9 +282,36 @@ void GraphicsPage::rendererChanged(const QString &renderer) { mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); - mAntiAliasingComboBox->clear(); - mResolutionComboBox->clear(); + antiAliasingComboBox->clear(); + resolutionComboBox->clear(); - mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); + antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); + resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); +} + +void GraphicsPage::slotFullScreenChanged(int state) +{ + if (state == Qt::Checked) { + standardRadioButton->toggle(); + customRadioButton->setEnabled(false); + customWidthSpinBox->setEnabled(false); + customHeightSpinBox->setEnabled(false); + } else { + customRadioButton->setEnabled(true); + customWidthSpinBox->setEnabled(true); + customHeightSpinBox->setEnabled(true); + } +} + +void GraphicsPage::slotStandardToggled(bool checked) +{ + if (checked) { + resolutionComboBox->setEnabled(true); + customWidthSpinBox->setEnabled(false); + customHeightSpinBox->setEnabled(false); + } else { + resolutionComboBox->setEnabled(false); + customWidthSpinBox->setEnabled(true); + customHeightSpinBox->setEnabled(true); + } } diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 48b9ff785..21039af43 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -16,16 +16,13 @@ # include "OgreD3D9Plugin.h" #endif -class QComboBox; -class QCheckBox; -class QStackedWidget; -class QSettings; +#include "ui_graphicspage.h" class GraphicsSettings; namespace Files { struct ConfigurationManager; } -class GraphicsPage : public QWidget +class GraphicsPage : public QWidget, private Ui::GraphicsPage { Q_OBJECT @@ -38,6 +35,10 @@ public: public slots: void rendererChanged(const QString &renderer); +private slots: + void slotFullScreenChanged(int state); + void slotStandardToggled(bool checked); + private: Ogre::Root *mOgre; Ogre::RenderSystem *mSelectedRenderSystem; @@ -50,22 +51,12 @@ private: Ogre::D3D9Plugin* mD3D9Plugin; #endif - QComboBox *mRendererComboBox; - - QStackedWidget *mDisplayStackedWidget; - - QComboBox *mAntiAliasingComboBox; - QComboBox *mResolutionComboBox; - QCheckBox *mVSyncCheckBox; - QCheckBox *mFullScreenCheckBox; - Files::ConfigurationManager &mCfgMgr; GraphicsSettings &mGraphicsSettings; QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); QStringList getAvailableResolutions(Ogre::RenderSystem *renderer); - void createPages(); void loadSettings(); }; diff --git a/apps/launcher/ui/graphicspage.ui b/apps/launcher/ui/graphicspage.ui index e04cd5855..5c330cebd 100644 --- a/apps/launcher/ui/graphicspage.ui +++ b/apps/launcher/ui/graphicspage.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 300 + 332 + 297
@@ -33,7 +33,7 @@ - GroupBox + Display @@ -73,9 +73,13 @@ - + - + + + 800 + + @@ -85,7 +89,11 @@ - + + + 600 + + @@ -101,7 +109,7 @@ Standard: - + true From 4c9d0563fe4d96f3ca50489b3ea2d4abbf48a44d Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 5 Mar 2013 03:13:39 +0100 Subject: [PATCH 884/916] WIP: Implementing the .ui for the DataFilesPage --- apps/launcher/CMakeLists.txt | 13 +- apps/launcher/datafilespage.cpp | 272 +++++++++--------- apps/launcher/datafilespage.hpp | 19 +- apps/launcher/maindialog.cpp | 9 +- components/CMakeLists.txt | 2 +- .../fileorderlist}/utils/comboboxlineedit.cpp | 0 .../fileorderlist}/utils/comboboxlineedit.hpp | 0 .../fileorderlist}/utils/profilescombobox.cpp | 0 .../fileorderlist}/utils/profilescombobox.hpp | 0 9 files changed, 155 insertions(+), 160 deletions(-) rename {apps/launcher => components/fileorderlist}/utils/comboboxlineedit.cpp (100%) rename {apps/launcher => components/fileorderlist}/utils/comboboxlineedit.hpp (100%) rename {apps/launcher => components/fileorderlist}/utils/profilescombobox.cpp (100%) rename {apps/launcher => components/fileorderlist}/utils/profilescombobox.hpp (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 206e94794..a1c228945 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -12,8 +12,6 @@ set(LAUNCHER settings/launchersettings.cpp utils/checkablemessagebox.cpp - utils/comboboxlineedit.cpp - utils/profilescombobox.cpp utils/textinputdialog.cpp launcher.rc @@ -33,8 +31,6 @@ set(LAUNCHER_HEADER settings/settingsbase.hpp utils/checkablemessagebox.hpp - utils/comboboxlineedit.hpp - utils/profilescombobox.hpp utils/textinputdialog.hpp ) @@ -49,15 +45,14 @@ set(LAUNCHER_HEADER_MOC model/pluginsproxymodel.hpp utils/checkablemessagebox.hpp - utils/comboboxlineedit.hpp - utils/profilescombobox.hpp utils/textinputdialog.hpp ) set(LAUNCHER_UI - ./ui/graphicspage.ui - ./ui/mainwindow.ui - ./ui/playpage.ui + ui/datafilespage.ui + ui/graphicspage.ui + ui/mainwindow.ui + ui/playpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index dd45c6602..d7dccbab6 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -10,13 +10,13 @@ #include #include +#include #include "model/pluginsproxymodel.hpp" #include "settings/gamesettings.hpp" #include "settings/launchersettings.hpp" -#include "utils/profilescombobox.hpp" #include "utils/textinputdialog.hpp" using namespace ESM; @@ -40,6 +40,8 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam , mLauncherSettings(launcherSettings) , QWidget(parent) { + setupUi(this); + // Models mDataFilesModel = new DataFilesModel(this); @@ -57,113 +59,117 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam mFilterProxyModel->setDynamicSortFilter(true); mFilterProxyModel->setSourceModel(mPluginsProxyModel); - // Filter toolbar - QLabel *filterLabel = new QLabel(tr("&Filter:"), this); - LineEdit *filterLineEdit = new LineEdit(this); - filterLabel->setBuddy(filterLineEdit); - - QToolBar *filterToolBar = new QToolBar(this); - filterToolBar->setMovable(false); - - // Create a container widget and a layout to get the spacer to work - QWidget *filterWidget = new QWidget(this); - QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget); - QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - filterLayout->addItem(hSpacer1); - filterLayout->addWidget(filterLabel); - filterLayout->addWidget(filterLineEdit); - - filterToolBar->addWidget(filterWidget); - QCheckBox checkBox; unsigned int height = checkBox.sizeHint().height() + 4; - mMastersTable = new QTableView(this); - mMastersTable->setModel(mMastersProxyModel); - mMastersTable->setObjectName("MastersTable"); - mMastersTable->setContextMenuPolicy(Qt::CustomContextMenu); - mMastersTable->setSortingEnabled(false); - mMastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mMastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - mMastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mMastersTable->setAlternatingRowColors(true); - mMastersTable->horizontalHeader()->setStretchLastSection(true); - mMastersTable->horizontalHeader()->hide(); + mastersTable->setModel(mMastersProxyModel); + mastersTable->setObjectName("MastersTable"); + mastersTable->setContextMenuPolicy(Qt::CustomContextMenu); + mastersTable->setSortingEnabled(false); + mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); + mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); + mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + mastersTable->setAlternatingRowColors(true); + mastersTable->horizontalHeader()->setStretchLastSection(true); + mastersTable->horizontalHeader()->hide(); // Set the row height to the size of the checkboxes - mMastersTable->verticalHeader()->setDefaultSectionSize(height); - mMastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mMastersTable->verticalHeader()->hide(); + mastersTable->verticalHeader()->setDefaultSectionSize(height); + mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + mastersTable->verticalHeader()->hide(); - mPluginsTable = new QTableView(this); - mPluginsTable->setModel(mFilterProxyModel); - mPluginsTable->setObjectName("PluginsTable"); - mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); - mPluginsTable->setSortingEnabled(false); - mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mPluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); - mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mPluginsTable->setAlternatingRowColors(true); - mPluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); - mPluginsTable->horizontalHeader()->setStretchLastSection(true); - mPluginsTable->horizontalHeader()->hide(); + pluginsTable->setModel(mFilterProxyModel); + pluginsTable->setObjectName("PluginsTable"); + pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); + pluginsTable->setSortingEnabled(false); + pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); + pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); + pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + pluginsTable->setAlternatingRowColors(true); + pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); + pluginsTable->horizontalHeader()->setStretchLastSection(true); + pluginsTable->horizontalHeader()->hide(); - mPluginsTable->verticalHeader()->setDefaultSectionSize(height); - mPluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + pluginsTable->verticalHeader()->setDefaultSectionSize(height); + pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - // Add both tables to a splitter - mSplitter = new QSplitter(this); - mSplitter->setOrientation(Qt::Horizontal); - mSplitter->setChildrenCollapsible(false); // Don't allow the widgets to be hidden - mSplitter->addWidget(mMastersTable); - mSplitter->addWidget(mPluginsTable); - - // Adjust the default widget widths inside the splitter + // Adjust the tableview widths inside the splitter QList sizeList; sizeList << mLauncherSettings.value(QString("General/MastersTable/width"), QString("200")).toInt(); sizeList << mLauncherSettings.value(QString("General/PluginTable/width"), QString("340")).toInt(); - mSplitter->setSizes(sizeList); + splitter->setSizes(sizeList); - // Bottom part with profile options - QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); +// // Filter toolbar +// QLabel *filterLabel = new QLabel(tr("&Filter:"), this); +// LineEdit *filterLineEdit = new LineEdit(this); +// filterLabel->setBuddy(filterLineEdit); - mProfilesComboBox = new ProfilesComboBox(this); - mProfilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); - mProfilesComboBox->setInsertPolicy(QComboBox::NoInsert); - mProfilesComboBox->setDuplicatesEnabled(false); - mProfilesComboBox->setEditEnabled(false); +// QToolBar *filterToolBar = new QToolBar(this); +// filterToolBar->setMovable(false); - mProfileToolBar = new QToolBar(this); - mProfileToolBar->setMovable(false); - mProfileToolBar->setIconSize(QSize(16, 16)); +// // Create a container widget and a layout to get the spacer to work +// QWidget *filterWidget = new QWidget(this); +// QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget); +// QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - mProfileToolBar->addWidget(profileLabel); - mProfileToolBar->addWidget(mProfilesComboBox); +// filterLayout->addItem(hSpacer1); +// filterLayout->addWidget(filterLabel); +// filterLayout->addWidget(filterLineEdit); - QVBoxLayout *pageLayout = new QVBoxLayout(this); +// filterToolBar->addWidget(filterWidget); - pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(mSplitter); - pageLayout->addWidget(mProfileToolBar); + + +// // Add both tables to a splitter +// mSplitter = new QSplitter(this); +// mSplitter->setOrientation(Qt::Horizontal); +// mSplitter->setChildrenCollapsible(false); // Don't allow the widgets to be hidden +// mSplitter->addWidget(mastersTable); +// mSplitter->addWidget(pluginsTable); + + + +// + +// // Bottom part with profile options +// QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); + +// profilesComboBox = new ProfilesComboBox(this); +// profilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); +// profilesComboBox->setInsertPolicy(QComboBox::NoInsert); +// profilesComboBox->setDuplicatesEnabled(false); +// profilesComboBox->setEditEnabled(false); + +// mProfileToolBar = new QToolBar(this); +// mProfileToolBar->setMovable(false); +// mProfileToolBar->setIconSize(QSize(16, 16)); + +// mProfileToolBar->addWidget(profileLabel); +// mProfileToolBar->addWidget(profilesComboBox); + +// QVBoxLayout *pageLayout = new QVBoxLayout(this); + +// pageLayout->addWidget(filterToolBar); +// pageLayout->addWidget(mSplitter); +// pageLayout->addWidget(mProfileToolBar); // Create a dialog for the new profile name input mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); - connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mMastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - connect(mPluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - connect(mMastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(pluginsTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); + connect(mastersTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - connect(mSplitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); + connect(splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(updateSplitter())); createActions(); setupDataFiles(); @@ -188,9 +194,9 @@ void DataFilesPage::createActions() connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); // Add the newly created actions to the toolbar - mProfileToolBar->addSeparator(); - mProfileToolBar->addAction(mNewProfileAction); - mProfileToolBar->addAction(mDeleteProfileAction); +// mProfileToolBar->addSeparator(); +// mProfileToolBar->addAction(mNewProfileAction); +// mProfileToolBar->addAction(mDeleteProfileAction); // Context menu actions mCheckAction = new QAction(tr("Check Selection"), this); @@ -226,25 +232,25 @@ void DataFilesPage::setupDataFiles() QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); if (!profiles.isEmpty()) - mProfilesComboBox->addItems(profiles); + profilesComboBox->addItems(profiles); // Add the current profile if empty - if (mProfilesComboBox->findText(profile) == -1) - mProfilesComboBox->addItem(profile); + if (profilesComboBox->findText(profile) == -1) + profilesComboBox->addItem(profile); - if (mProfilesComboBox->findText(QString("Default")) == -1) - mProfilesComboBox->addItem(QString("Default")); + if (profilesComboBox->findText(QString("Default")) == -1) + profilesComboBox->addItem(QString("Default")); if (profile.isEmpty() || profile == QLatin1String("Default")) { - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(QString("Default"))); + profilesComboBox->setCurrentIndex(profilesComboBox->findText(QString("Default"))); } else { - mProfilesComboBox->setEditEnabled(true); - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); + profilesComboBox->setEditEnabled(true); + profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile)); } // We do this here to prevent deletion of profiles when initializing the combobox - connect(mProfilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); - connect(mProfilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); + connect(profilesComboBox, SIGNAL(profileRenamed(QString,QString)), this, SLOT(profileRenamed(QString,QString))); + connect(profilesComboBox, SIGNAL(profileChanged(QString,QString)), this, SLOT(profileChanged(QString,QString))); loadSettings(); @@ -283,7 +289,7 @@ void DataFilesPage::saveSettings() QString profile = mLauncherSettings.value(QString("Profiles/currentprofile")); if (profile.isEmpty()) { - profile = mProfilesComboBox->currentText(); + profile = profilesComboBox->currentText(); mLauncherSettings.setValue(QString("Profiles/currentprofile"), profile); } @@ -313,8 +319,8 @@ void DataFilesPage::newProfile() { if (mNewProfileDialog->exec() == QDialog::Accepted) { QString profile = mNewProfileDialog->lineEdit()->text(); - mProfilesComboBox->addItem(profile); - mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(profile)); + profilesComboBox->addItem(profile); + profilesComboBox->setCurrentIndex(profilesComboBox->findText(profile)); } } @@ -326,7 +332,7 @@ void DataFilesPage::updateOkButton(const QString &text) return; } - (mProfilesComboBox->findText(text) == -1) + (profilesComboBox->findText(text) == -1) ? mNewProfileDialog->setOkButtonEnabled(true) : mNewProfileDialog->setOkButtonEnabled(false); } @@ -335,7 +341,7 @@ void DataFilesPage::updateSplitter() { // Sigh, update the saved splitter size in settings only when moved // Since getting mSplitter->sizes() if page is hidden returns invalid values - QList sizes = mSplitter->sizes(); + QList sizes = splitter->sizes(); mLauncherSettings.setValue(QString("General/MastersTable/width"), QString::number(sizes.at(0))); mLauncherSettings.setValue(QString("General/PluginsTable/width"), QString::number(sizes.at(1))); @@ -344,28 +350,28 @@ void DataFilesPage::updateSplitter() void DataFilesPage::updateViews() { // Ensure the columns are hidden because sort() re-enables them - mMastersTable->setColumnHidden(1, true); - mMastersTable->setColumnHidden(2, true); - mMastersTable->setColumnHidden(3, true); - mMastersTable->setColumnHidden(4, true); - mMastersTable->setColumnHidden(5, true); - mMastersTable->setColumnHidden(6, true); - mMastersTable->setColumnHidden(7, true); - mMastersTable->setColumnHidden(8, true); + mastersTable->setColumnHidden(1, true); + mastersTable->setColumnHidden(2, true); + mastersTable->setColumnHidden(3, true); + mastersTable->setColumnHidden(4, true); + mastersTable->setColumnHidden(5, true); + mastersTable->setColumnHidden(6, true); + mastersTable->setColumnHidden(7, true); + mastersTable->setColumnHidden(8, true); - mPluginsTable->setColumnHidden(1, true); - mPluginsTable->setColumnHidden(2, true); - mPluginsTable->setColumnHidden(3, true); - mPluginsTable->setColumnHidden(4, true); - mPluginsTable->setColumnHidden(5, true); - mPluginsTable->setColumnHidden(6, true); - mPluginsTable->setColumnHidden(7, true); - mPluginsTable->setColumnHidden(8, true); + pluginsTable->setColumnHidden(1, true); + pluginsTable->setColumnHidden(2, true); + pluginsTable->setColumnHidden(3, true); + pluginsTable->setColumnHidden(4, true); + pluginsTable->setColumnHidden(5, true); + pluginsTable->setColumnHidden(6, true); + pluginsTable->setColumnHidden(7, true); + pluginsTable->setColumnHidden(8, true); } void DataFilesPage::deleteProfile() { - QString profile = mProfilesComboBox->currentText(); + QString profile = profilesComboBox->currentText(); if (profile.isEmpty()) return; @@ -386,26 +392,26 @@ void DataFilesPage::deleteProfile() mLauncherSettings.remove(QString("Profiles/") + profile + QString("/plugin")); // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(profile)); + profilesComboBox->removeItem(profilesComboBox->findText(profile)); } } void DataFilesPage::check() { - if (mPluginsTable->hasFocus()) + if (pluginsTable->hasFocus()) setPluginsCheckstates(Qt::Checked); - if (mMastersTable->hasFocus()) + if (mastersTable->hasFocus()) setMastersCheckstates(Qt::Checked); } void DataFilesPage::uncheck() { - if (mPluginsTable->hasFocus()) + if (pluginsTable->hasFocus()) setPluginsCheckstates(Qt::Unchecked); - if (mMastersTable->hasFocus()) + if (mastersTable->hasFocus()) setMastersCheckstates(Qt::Unchecked); } @@ -414,16 +420,16 @@ void DataFilesPage::refresh() // mDataFilesModel->sort(0); // Refresh the plugins table - mPluginsTable->scrollToTop(); + pluginsTable->scrollToTop(); } void DataFilesPage::setMastersCheckstates(Qt::CheckState state) { - if (!mMastersTable->selectionModel()->hasSelection()) { + if (!mastersTable->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = mMastersTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes(); foreach (const QModelIndex &index, indexes) { @@ -441,11 +447,11 @@ void DataFilesPage::setMastersCheckstates(Qt::CheckState state) void DataFilesPage::setPluginsCheckstates(Qt::CheckState state) { - if (!mPluginsTable->selectionModel()->hasSelection()) { + if (!pluginsTable->selectionModel()->hasSelection()) { return; } - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes(); foreach (const QModelIndex &index, indexes) { @@ -509,16 +515,16 @@ void DataFilesPage::profileChanged(const QString &previous, const QString &curre // Prevent the deletion of the default profile if (current == QLatin1String("Default")) { mDeleteProfileAction->setEnabled(false); - mProfilesComboBox->setEditEnabled(false); + profilesComboBox->setEditEnabled(false); } else { mDeleteProfileAction->setEnabled(true); - mProfilesComboBox->setEditEnabled(true); + profilesComboBox->setEditEnabled(true); } if (previous.isEmpty()) return; - if (mProfilesComboBox->findText(previous) == -1) + if (profilesComboBox->findText(previous) == -1) return; // Profile was deleted // Store the previous profile @@ -543,7 +549,7 @@ void DataFilesPage::profileRenamed(const QString &previous, const QString &curre mLauncherSettings.remove(QString("Profiles/") + previous + QString("/plugin")); // Remove the profile from the combobox - mProfilesComboBox->removeItem(mProfilesComboBox->findText(previous)); + profilesComboBox->removeItem(profilesComboBox->findText(previous)); loadSettings(); @@ -558,11 +564,11 @@ void DataFilesPage::showContextMenu(const QPoint &point) return; if (object->objectName() == QLatin1String("PluginsTable")) { - if (!mPluginsTable->selectionModel()->hasSelection()) + if (!pluginsTable->selectionModel()->hasSelection()) return; - QPoint globalPos = mPluginsTable->mapToGlobal(point); - QModelIndexList indexes = mPluginsTable->selectionModel()->selectedIndexes(); + QPoint globalPos = pluginsTable->mapToGlobal(point); + QModelIndexList indexes = pluginsTable->selectionModel()->selectedIndexes(); // Show the check/uncheck actions depending on the state of the selected items mUncheckAction->setEnabled(false); @@ -589,11 +595,11 @@ void DataFilesPage::showContextMenu(const QPoint &point) } if (object->objectName() == QLatin1String("MastersTable")) { - if (!mMastersTable->selectionModel()->hasSelection()) + if (!mastersTable->selectionModel()->hasSelection()) return; - QPoint globalPos = mMastersTable->mapToGlobal(point); - QModelIndexList indexes = mMastersTable->selectionModel()->selectedIndexes(); + QPoint globalPos = mastersTable->mapToGlobal(point); + QModelIndexList indexes = mastersTable->selectionModel()->selectedIndexes(); // Show the check/uncheck actions depending on the state of the selected items mUncheckAction->setEnabled(false); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index dd69d7489..e98b09aef 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -4,33 +4,28 @@ #include #include -class QTableView; +#include "ui_datafilespage.h" + class QSortFilterProxyModel; class QAction; -class QToolBar; -class QSplitter; class QMenu; -class ProfilesComboBox; class DataFilesModel; class TextInputDialog; -class ProfilesComboBox; class GameSettings; class LauncherSettings; class PluginsProxyModel; namespace Files { struct ConfigurationManager; } -class DataFilesPage : public QWidget +class DataFilesPage : public QWidget, private Ui::DataFilesPage { Q_OBJECT public: DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0); - ProfilesComboBox *mProfilesComboBox; - void writeConfig(QString profile = QString()); void saveSettings(); @@ -60,13 +55,13 @@ private: QSortFilterProxyModel *mFilterProxyModel; - QTableView *mMastersTable; - QTableView *mPluginsTable; +// QTableView *mMastersTable; +// QTableView *mPluginsTable; - QToolBar *mProfileToolBar; +// QToolBar *mProfileToolBar; QMenu *mContextMenu; - QSplitter *mSplitter; +// QSplitter *mSplitter; QAction *mNewProfileAction; QAction *mDeleteProfileAction; diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 5621b75c0..cab763b10 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -3,7 +3,6 @@ #include #include "utils/checkablemessagebox.hpp" -#include "utils/profilescombobox.hpp" #include "playpage.hpp" #include "graphicspage.hpp" @@ -94,8 +93,8 @@ void MainDialog::createPages() mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage - mPlayPage->setProfilesComboBoxModel(mDataFilesPage->mProfilesComboBox->model()); - mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); +// mPlayPage->setProfilesComboBoxModel(mDataFilesPage->mProfilesComboBox->model()); +// mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); // Add the pages to the stacked widget pagesWidget->addWidget(mPlayPage); @@ -107,8 +106,8 @@ void MainDialog::createPages() connect(mPlayPage, SIGNAL(playButtonClicked()), this, SLOT(play())); - connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); - connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); +// connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); +// connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00342e2ac..7c52ab12c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -71,7 +71,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui) if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (fileorderlist datafileslist model/modelitem model/datafilesmodel model/esm/esmfile - utils/filedialog utils/lineedit utils/naturalsort + utils/profilescombobox utils/comboboxlineedit utils/lineedit utils/naturalsort ) include(${QT_USE_FILE}) diff --git a/apps/launcher/utils/comboboxlineedit.cpp b/components/fileorderlist/utils/comboboxlineedit.cpp similarity index 100% rename from apps/launcher/utils/comboboxlineedit.cpp rename to components/fileorderlist/utils/comboboxlineedit.cpp diff --git a/apps/launcher/utils/comboboxlineedit.hpp b/components/fileorderlist/utils/comboboxlineedit.hpp similarity index 100% rename from apps/launcher/utils/comboboxlineedit.hpp rename to components/fileorderlist/utils/comboboxlineedit.hpp diff --git a/apps/launcher/utils/profilescombobox.cpp b/components/fileorderlist/utils/profilescombobox.cpp similarity index 100% rename from apps/launcher/utils/profilescombobox.cpp rename to components/fileorderlist/utils/profilescombobox.cpp diff --git a/apps/launcher/utils/profilescombobox.hpp b/components/fileorderlist/utils/profilescombobox.hpp similarity index 100% rename from apps/launcher/utils/profilescombobox.hpp rename to components/fileorderlist/utils/profilescombobox.hpp From 75cf009101828d8f83c98eb0915bede65c1c54dd Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 5 Mar 2013 03:47:57 +0100 Subject: [PATCH 885/916] Finished implementing the .ui file for the DataFilesPage --- apps/launcher/datafilespage.cpp | 32 ++++++++++++++++++++++++++------ apps/launcher/datafilespage.hpp | 12 +++++++++++- apps/launcher/maindialog.cpp | 8 ++++---- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index d7dccbab6..069cdd9ac 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -157,6 +157,8 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam // Create a dialog for the new profile name input mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); + connect(profilesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int))); + connect(mNewProfileDialog->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(updateOkButton(QString))); connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); @@ -182,7 +184,7 @@ void DataFilesPage::createActions() refreshAction->setShortcut(QKeySequence(tr("F5"))); connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); - // Profile actions + // We can't create actions inside the .ui file mNewProfileAction = new QAction(QIcon::fromTheme("document-new"), tr("&New Profile"), this); mNewProfileAction->setToolTip(tr("New Profile")); mNewProfileAction->setShortcut(QKeySequence(tr("Ctrl+N"))); @@ -190,13 +192,11 @@ void DataFilesPage::createActions() mDeleteProfileAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete Profile"), this); mDeleteProfileAction->setToolTip(tr("Delete Profile")); - mDeleteProfileAction->setShortcut(QKeySequence(tr("Delete"))); connect(mDeleteProfileAction, SIGNAL(triggered()), this, SLOT(deleteProfile())); - // Add the newly created actions to the toolbar -// mProfileToolBar->addSeparator(); -// mProfileToolBar->addAction(mNewProfileAction); -// mProfileToolBar->addAction(mDeleteProfileAction); + // Add the newly created actions to the toolbuttons + newProfileButton->setDefaultAction(mNewProfileAction); + deleteProfileButton->setDefaultAction(mDeleteProfileAction); // Context menu actions mCheckAction = new QAction(tr("Check Selection"), this); @@ -369,6 +369,26 @@ void DataFilesPage::updateViews() pluginsTable->setColumnHidden(8, true); } +void DataFilesPage::setProfilesComboBoxIndex(int index) +{ + profilesComboBox->setCurrentIndex(index); +} + +void DataFilesPage::slotCurrentIndexChanged(int index) +{ + emit profileChanged(index); +} + +QAbstractItemModel* DataFilesPage::profilesComboBoxModel() +{ + return profilesComboBox->model(); +} + +int DataFilesPage::profilesComboBoxIndex() +{ + return profilesComboBox->currentIndex(); +} + void DataFilesPage::deleteProfile() { QString profile = profilesComboBox->currentText(); diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index e98b09aef..301abf59b 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -7,11 +7,11 @@ #include "ui_datafilespage.h" class QSortFilterProxyModel; +class QAbstractItemModel; class QAction; class QMenu; class DataFilesModel; - class TextInputDialog; class GameSettings; class LauncherSettings; @@ -26,12 +26,19 @@ class DataFilesPage : public QWidget, private Ui::DataFilesPage public: DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gameSettings, LauncherSettings &launcherSettings, QWidget *parent = 0); + QAbstractItemModel* profilesComboBoxModel(); + int profilesComboBoxIndex(); + void writeConfig(QString profile = QString()); void saveSettings(); +signals: + void profileChanged(int index); public slots: void setCheckState(QModelIndex index); + void setProfilesComboBoxIndex(int index); + void filterChanged(const QString filter); void showContextMenu(const QPoint &point); void profileChanged(const QString &previous, const QString ¤t); @@ -47,6 +54,9 @@ public slots: void uncheck(); void refresh(); +private slots: + void slotCurrentIndexChanged(int index); + private: DataFilesModel *mDataFilesModel; diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index cab763b10..6a3965cc9 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -93,8 +93,8 @@ void MainDialog::createPages() mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this); // Set the combobox of the play page to imitate the combobox on the datafilespage -// mPlayPage->setProfilesComboBoxModel(mDataFilesPage->mProfilesComboBox->model()); -// mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->mProfilesComboBox->currentIndex()); + mPlayPage->setProfilesComboBoxModel(mDataFilesPage->profilesComboBoxModel()); + mPlayPage->setProfilesComboBoxIndex(mDataFilesPage->profilesComboBoxIndex()); // Add the pages to the stacked widget pagesWidget->addWidget(mPlayPage); @@ -106,8 +106,8 @@ void MainDialog::createPages() connect(mPlayPage, SIGNAL(playButtonClicked()), this, SLOT(play())); -// connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage->mProfilesComboBox, SLOT(setCurrentIndex(int))); -// connect(mDataFilesPage->mProfilesComboBox, SIGNAL(currentIndexChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); + connect(mPlayPage, SIGNAL(profileChanged(int)), mDataFilesPage, SLOT(setProfilesComboBoxIndex(int))); + connect(mDataFilesPage, SIGNAL(profileChanged(int)), mPlayPage, SLOT(setProfilesComboBoxIndex(int))); } From 770d8af931ea7ad75c3a978761eb36fcd4e1e37c Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Tue, 5 Mar 2013 03:57:27 +0100 Subject: [PATCH 886/916] Forgot to add the DataFilesPage .ui --- apps/launcher/ui/datafilespage.ui | 125 ++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 apps/launcher/ui/datafilespage.ui diff --git a/apps/launcher/ui/datafilespage.ui b/apps/launcher/ui/datafilespage.ui new file mode 100644 index 000000000..91b5475e6 --- /dev/null +++ b/apps/launcher/ui/datafilespage.ui @@ -0,0 +1,125 @@ + + + DataFilesPage + + + + 0 + 0 + 520 + 256 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Filter: + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + false + + + + + + + + + + + Current Profile: + + + + + + + + 0 + 0 + + + + + + + + New Profile + + + &New Profile + + + true + + + + + + + Delete Profile + + + Delete Profile + + + Ctrl+D + + + true + + + + + + + + + + LineEdit + QLineEdit +

components/fileorderlist/utils/lineedit.hpp
+ + + ProfilesComboBox + QComboBox +
components/fileorderlist/utils/profilescombobox.hpp
+
+ + + + From ce49ad54a1ef73a557ef0a6d32362d21718ed2e0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:02:05 +0100 Subject: [PATCH 887/916] some cleanup and fixing --- components/esm/loadglob.cpp | 8 ++------ components/esm/variant.cpp | 37 ++++++++++++++++++++++--------------- components/esm/variant.hpp | 2 +- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 0cb6d0a41..ccb519acd 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -1,17 +1,13 @@ #include "loadglob.hpp" -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { - - void Global::load(ESMReader &esm) + void Global::load (ESMReader &esm) { mValue.read (esm, ESM::Variant::Format_Global); } - void Global::save(ESMWriter &esm) + void Global::save (ESMWriter &esm) { mValue.write (esm, ESM::Variant::Format_Global); } diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index bf8d2069b..98786c20e 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -37,7 +37,7 @@ ESM::VarType ESM::Variant::getType() const return mType; } -std::string ESM::Variant::toString() const +std::string ESM::Variant::getString() const { if (!mData) throw std::runtime_error ("can not convert empty variant to string"); @@ -81,23 +81,30 @@ void ESM::Variant::read (ESMReader& esm, Format format) } else // GMST { - esm.getSubName(); - NAME name = esm.retSubName(); - - if (name=="STRV") + if (!esm.hasMoreSubs()) { - type = VT_String; - } - else if (name=="INTV") - { - type = VT_Int; - } - else if (name=="FLTV") - { - type = VT_Float; + type = VT_None; } else - esm.fail ("invalid subrecord: " + name.toString()); + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="STRV") + { + type = VT_String; + } + else if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } } setType (type); diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index b50bb1d2f..b78d647a8 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -45,7 +45,7 @@ namespace ESM VarType getType() const; - std::string toString() const; + std::string getString() const; ///< Will throw an exception, if value can not be represented as a string. int getInteger() const; From ba4907fbaf7ed8d1dee768569b912bf7ee7641cf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:02:27 +0100 Subject: [PATCH 888/916] use new Variant type for GMSTs --- apps/esmtool/record.cpp | 18 +----- apps/opencs/model/doc/document.cpp | 10 ++- apps/opencs/model/world/columns.hpp | 31 ++++++--- apps/opencs/model/world/data.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 11 ++-- apps/openmw/mwworld/worldimp.cpp | 14 ++-- components/esm/loadgmst.cpp | 89 ++++---------------------- components/esm/loadgmst.hpp | 10 ++- 8 files changed, 55 insertions(+), 129 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 929201417..e4de63dd4 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -719,23 +719,7 @@ void Record::print() template<> void Record::print() { - std::cout << " Value: "; - switch (mData.mType) { - case ESM::VT_String: - std::cout << "'" << mData.mStr << "' (std::string)"; - break; - - case ESM::VT_Float: - std::cout << mData.mF << " (float)"; - break; - - case ESM::VT_Int: - std::cout << mData.mI << " (int)"; - break; - - default: - std::cout << "unknown type"; - } + std::cout << " " << mData.mValue << std::endl; } template<> diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index f6df1f499..6a76b0b6c 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -116,8 +116,7 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sFloats[i]; - gmst.mF = 0; - gmst.mType = ESM::VT_Float; + gmst.mValue.setType (ESM::VT_Float); addOptionalGmst (gmst); } @@ -125,8 +124,7 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sIntegers[i]; - gmst.mI = 0; - gmst.mType = ESM::VT_Long; + gmst.mValue.setType (ESM::VT_Int); addOptionalGmst (gmst); } @@ -134,8 +132,8 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sStrings[i]; - gmst.mStr = ""; - gmst.mType = ESM::VT_String; + gmst.mValue.setType (ESM::VT_String); + gmst.mValue.setString (""); addOptionalGmst (gmst); } } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 8855edc46..270987ec1 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -100,13 +100,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return static_cast (record.get().mType); + return static_cast (record.get().mValue.getType()); } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mType = static_cast (data.toInt()); + record2.mValue.setType (static_cast (data.toInt())); record.setModified (record2); } @@ -123,11 +123,11 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - switch (record.get().mType) + switch (record.get().mValue.getType()) { - case ESM::VT_String: return record.get().mStr.c_str(); break; - case ESM::VT_Int: return record.get().mI; break; - case ESM::VT_Float: return record.get().mF; break; + case ESM::VT_String: return record.get().mValue.getString().c_str(); break; + case ESM::VT_Int: return record.get().mValue.getInteger(); break; + case ESM::VT_Float: return record.get().mValue.getFloat(); break; default: return QVariant(); } @@ -137,11 +137,22 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - switch (record2.mType) + switch (record2.mValue.getType()) { - case ESM::VT_String: record2.mStr = data.toString().toUtf8().constData(); break; - case ESM::VT_Int: record2.mI = data.toInt(); break; - case ESM::VT_Float: record2.mF = data.toFloat(); break; + case ESM::VT_String: + + record2.mValue.setString (data.toString().toUtf8().constData()); + break; + + case ESM::VT_Int: + + record2.mValue.setInteger (data.toInt()); + break; + + case ESM::VT_Float: + + record2.mValue.setFloat (data.toFloat()); + break; default: break; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c59763f51..d4704b0c6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "idtable.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1dc11f2c4..efdb86400 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -569,7 +569,7 @@ void WindowManager::messageBox (const std::string& message, const std::vectorcreateMessageBox(message); } - + else { mMessageBoxManager->createInteractiveMessageBox(message, buttons); @@ -592,8 +592,9 @@ std::string WindowManager::getGameSettingString(const std::string &id, const std const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().search(id); - if (setting && setting->mType == ESM::VT_String) - return setting->getString(); + if (setting && setting->mValue.getType()==ESM::VT_String) + return setting->mValue.getString(); + return default_; } @@ -774,8 +775,8 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().find(tag); - if (setting && setting->mType == ESM::VT_String) - _result = setting->getString(); + if (setting && setting->mValue.getType()==ESM::VT_String) + _result = setting->mValue.getString(); else _result = tag; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 90f26096e..1de0559d9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -198,7 +198,7 @@ namespace MWWorld for (std::vector::size_type i = 0; i < master.size(); i++, idx++) { boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); - + std::cout << "Loading ESM " << masterPath.string() << "\n"; // This parses the ESM file @@ -210,11 +210,11 @@ namespace MWWorld mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } - + for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) { boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i])); - + std::cout << "Loading ESP " << pluginPath.string() << "\n"; // This parses the ESP file @@ -226,7 +226,7 @@ namespace MWWorld mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } - + mStore.setUp(); mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); @@ -363,10 +363,8 @@ namespace MWWorld const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().search("sDefaultCellname"); - if (setting && setting->mType == ESM::VT_String) - name = setting->getString(); - else - name = "Wilderness"; + if (setting && setting->mValue.getType()==ESM::VT_String) + name = setting->mValue.getString(); } } diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index e9852ec07..fe1cc1b04 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -1,104 +1,39 @@ #include "loadgmst.hpp" -#include - -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { - -void GameSetting::load(ESMReader &esm) -{ - assert(mId != ""); - - // We are apparently allowed to be empty - if (!esm.hasMoreSubs()) + void GameSetting::load (ESMReader &esm) { - mType = VT_None; - return; + mValue.read (esm, ESM::Variant::Format_Gmst); } - // Load some data - esm.getSubName(); - NAME n = esm.retSubName(); - if (n == "STRV") + void GameSetting::save (ESMWriter &esm) { - mStr = esm.getHString(); - mType = VT_String; + mValue.write (esm, ESM::Variant::Format_Gmst); } - else if (n == "INTV") - { - esm.getHT(mI); - mType = VT_Int; - } - else if (n == "FLTV") - { - esm.getHT(mF); - mType = VT_Float; - } - else - esm.fail("Unwanted subrecord type"); -} -void GameSetting::save(ESMWriter &esm) -{ - switch(mType) + int GameSetting::getInt() const { - case VT_String: esm.writeHNString("STRV", mStr); break; - case VT_Int: esm.writeHNT("INTV", mI); break; - case VT_Float: esm.writeHNT("FLTV", mF); break; - default: break; + return mValue.getInteger(); } -} -int GameSetting::getInt() const -{ - switch (mType) + float GameSetting::getFloat() const { - case VT_Float: return static_cast (mF); - case VT_Int: return mI; - default: throw std::runtime_error ("GMST " + mId + " is not of a numeric type"); + return mValue.getFloat(); } -} -float GameSetting::getFloat() const -{ - switch (mType) + std::string GameSetting::getString() const { - case VT_Float: return mF; - case VT_Int: return mI; - default: throw std::runtime_error ("GMST " + mId + " is not of a numeric type"); + return mValue.getString(); } -} - -std::string GameSetting::getString() const -{ - if (mType==VT_String) - return mStr; - - throw std::runtime_error ("GMST " + mId + " is not a string"); -} void GameSetting::blank() { - mStr.clear(); - mI = 0; - mF = 0; - mType = VT_Float; + mValue.setType (ESM::VT_None); } bool operator== (const GameSetting& left, const GameSetting& right) { - if (left.mType!=right.mType) - return false; - - switch (left.mType) - { - case VT_Float: return left.mF==right.mF; - case VT_Int: return left.mI==right.mI; - case VT_String: return left.mStr==right.mStr; - default: return false; - } + return left.mValue==right.mValue; } } diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 12f212081..a6e0c2ecb 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -3,7 +3,6 @@ #include -#include "defs.hpp" #include "variant.hpp" namespace ESM @@ -20,14 +19,13 @@ class ESMWriter; struct GameSetting { std::string mId; - // One of these is used depending on the variable type - std::string mStr; - int mI; - float mF; - VarType mType; + + Variant mValue; void load(ESMReader &esm); + /// \todo remove the get* functions (redundant, since mValue as equivalent functions now). + int getInt() const; ///< Throws an exception if GMST is not of type int or float. From 1b19ab6028929cc6384afaf8c634cd84abeb2817 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:15:03 +0100 Subject: [PATCH 889/916] fixed gmst integers --- components/esm/variantimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index e99cc50b5..1b8cf4f87 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -156,8 +156,8 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT } else // GMST { - if (type==VT_Int) - esm.fail ("unsupported global variable integer type"); + if (type!=VT_Int) + esm.fail ("unsupported gmst variable integer type"); esm.getHT (mValue); } From 1489570b097bc31103fa1e03ec49ba2081a61a6c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 09:40:41 +0100 Subject: [PATCH 890/916] change variant in info record to new type --- apps/esmtool/record.cpp | 9 ++--- apps/openmw/mwdialogue/selectwrapper.cpp | 9 +++-- components/esm/loadinfo.cpp | 25 ++----------- components/esm/loadinfo.hpp | 46 ++---------------------- components/esm/variant.cpp | 21 ++++++++++- components/esm/variant.hpp | 3 +- components/esm/variantimp.cpp | 32 +++++++++++++---- 7 files changed, 59 insertions(+), 86 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e4de63dd4..38fddd6b9 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -112,14 +112,11 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case '5': oper_str = ">="; break; } - std::string value_str = "??"; - if (ss.mType == ESM::VT_Int) - value_str = str(boost::format("%d") % ss.mI); - else if (ss.mType == ESM::VT_Float) - value_str = str(boost::format("%f") % ss.mF); + std::ostringstream stream; + stream << ss.mValue; std::string result = str(boost::format("%-12s %-32s %2s %s") - % type_str % func_str % oper_str % value_str); + % type_str % func_str % oper_str % stream.str()); return result; } diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 9cc528a11..9d705f6be 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -31,14 +31,13 @@ namespace template bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1) { - if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || - select.mType==ESM::VT_Long) + if (select.mValue.getType()==ESM::VT_Int) { - return selectCompareImp (select.mSelectRule[4], value1, select.mI); + return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getInteger()); } - else if (select.mType==ESM::VT_Float) + else if (select.mValue.getType()==ESM::VT_Float) { - return selectCompareImp (select.mSelectRule[4], value1, select.mF); + return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getFloat()); } else throw std::runtime_error ( diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index f237cf780..90f8fcf35 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -84,22 +84,8 @@ void DialInfo::load(ESMReader &esm) SelectStruct ss; ss.mSelectRule = esm.getHString(); - esm.isEmptyOrGetName(); - if (subName.val == REC_INTV) - { - ss.mType = VT_Int; - esm.getHT(ss.mI); - } - else if (subName.val == REC_FLTV) - { - ss.mType = VT_Float; - esm.getHT(ss.mF); - } - else - esm.fail( - "INFO.SCVR must precede INTV or FLTV, not " - + subName.toString()); + ss.mValue.read (esm, Variant::Format_Info); mSelects.push_back(ss); @@ -152,16 +138,11 @@ void DialInfo::save(ESMWriter &esm) for (std::vector::iterator it = mSelects.begin(); it != mSelects.end(); ++it) { esm.writeHNString("SCVR", it->mSelectRule); - switch(it->mType) - { - case VT_Int: esm.writeHNT("INTV", it->mI); break; - case VT_Float: esm.writeHNT("FLTV", it->mF); break; - default: break; - } + it->mValue.write (esm, Variant::Format_Info); } esm.writeHNOString("BNAM", mResultScript); - + switch(mQuestStatus) { case QS_Name: esm.writeHNT("QSTN",'\1'); break; diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index ca08c3b55..2361ed9eb 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -13,8 +13,6 @@ namespace ESM class ESMReader; class ESMWriter; -// NOT DONE - /* * Dialogue information. A series of these follow after DIAL records, * and form a linked list of dialogue items. @@ -44,9 +42,7 @@ struct DialInfo struct SelectStruct { std::string mSelectRule; // This has a complicated format - float mF; // Only one of 'f' or 'i' is used - int mI; - VarType mType; + Variant mValue; }; // Journal quest indices (introduced with the quest system in Tribunal) @@ -94,8 +90,7 @@ struct DialInfo REC_SNAM = 0x4d414e53, REC_NAME = 0x454d414e, REC_SCVR = 0x52564353, - REC_INTV = 0x56544e49, - REC_FLTV = 0x56544c46, + REC_BNAM = 0x4d414e42, REC_QSTN = 0x4e545351, REC_QSTF = 0x46545351, @@ -107,42 +102,5 @@ struct DialInfo void save(ESMWriter &esm); }; -/* - Some old and unused D code and comments, that might be useful later: - -------- - - // We only need to put each item in ONE list. For if your NPC - // matches this response, then it must match ALL criteria, thus it - // will have to look up itself in all the lists. I think the order - // is well optimized in making the lists as small as possible. - if(this.actor.index != -1) actorDial[this.actor][parent]++; - else if(cell != "") cellDial[cell][parent]++; - else if(this.Class != -1) classDial[this.Class][parent]++; - else if(this.npcFaction != -1) - factionDial[this.npcFaction][parent]++; - else if(this.race != -1) raceDial[this.race][parent]++; - else allDial[parent]++; // Lists dialogues that might - // apply to all npcs. - */ - -// List of dialogue topics (and greetings, voices, etc.) that -// reference other objects. Eg. raceDial is indexed by the indices of -// all races referenced. The value of raceDial is a new AA, which is -// basically used as a map (the int value is just a count and isn't -// used for anything important.) The indices (or elements of the map) -// are the dialogues that reference the given race. I use an AA -// instead of a list or array, since each dialogue can be added lots -// of times. - -/* -int allDial[Dialogue*]; -int classDial[int][Dialogue*]; -int factionDial[int][Dialogue*]; -int actorDial[Item][Dialogue*]; -// If I look up cells on cell load, I don't have to resolve these -// names into anything! -int cellDial[char[]][Dialogue*]; -int raceDial[int][Dialogue*]; -*/ } #endif diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index 98786c20e..d25072e54 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -79,7 +79,7 @@ void ESM::Variant::read (ESMReader& esm, Format format) else esm.fail ("illegal global variable type " + typeId); } - else // GMST + else if (format==Format_Gmst) { if (!esm.hasMoreSubs()) { @@ -106,6 +106,22 @@ void ESM::Variant::read (ESMReader& esm, Format format) esm.fail ("invalid subrecord: " + name.toString()); } } + else // info + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } setType (type); @@ -125,6 +141,9 @@ void ESM::Variant::write (ESMWriter& esm, Format format) const if (format==Format_Global) throw std::runtime_error ("can not serialise variant of type none to global format"); + if (format==Format_Info) + throw std::runtime_error ("can not serialise variant of type none to info format"); + // nothing to do here for GMST format } else diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index b78d647a8..8c5f3b3d4 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -32,7 +32,8 @@ namespace ESM enum Format { Format_Global, - Format_Gmst + Format_Gmst, + Format_Info }; Variant(); diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index 1b8cf4f87..160402aa4 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -78,6 +78,9 @@ void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarTy if (format==Variant::Format_Global) esm.fail ("global variables of type string not supported"); + if (format==Variant::Format_Info) + esm.fail ("info variables of type string not supported"); + // GMST mValue = esm.getHString(); } @@ -90,6 +93,9 @@ void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarT if (format==Variant::Format_Global) throw std::runtime_error ("global variables of type string not supported"); + if (format==Variant::Format_Info) + throw std::runtime_error ("info variables of type string not supported"); + // GMST esm.writeHNString ("STRV", mValue); } @@ -154,10 +160,16 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT else esm.fail ("unsupported global variable integer type"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { if (type!=VT_Int) - esm.fail ("unsupported gmst variable integer type"); + { + std::ostringstream stream; + stream + << "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info") + << " variable integer type"; + esm.fail (stream.str()); + } esm.getHT (mValue); } @@ -179,10 +191,16 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var else throw std::runtime_error ("unsupported global variable integer type"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { if (type==VT_Int) - throw std::runtime_error ("unsupported global variable integer type"); + { + std::ostringstream stream; + stream + << "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info") + << " variable integer type"; + throw std::runtime_error (stream.str()); + } esm.writeHNT ("INTV", mValue); } @@ -234,7 +252,7 @@ void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarTyp { esm.getHNT (mValue, "FLTV"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { esm.getHT (mValue); } @@ -250,9 +268,9 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy esm.writeHNString ("FNAM", "f"); esm.writeHNT ("FLTV", mValue); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { - esm.writeHNT ("INTV", mValue); + esm.writeHNT ("FLTV", mValue); } } From 46de45b9a2a70ad4a67995a690a5ed2265f835c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 11:37:13 +0100 Subject: [PATCH 891/916] added var type column to globals --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 20 ++++++++++++++++---- apps/opencs/model/world/data.cpp | 5 +++-- apps/opencs/view/doc/viewmanager.cpp | 6 +++++- apps/opencs/view/world/vartypedelegate.cpp | 2 +- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 6a76b0b6c..e709cc5bf 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -152,7 +152,7 @@ void CSMDoc::Document::addOptionalGlobals() { ESM::Global global; global.mId = sGlobals[i]; - global.mValue.setType (ESM::VT_Int); + global.mValue.setType (ESM::VT_Long); addOptionalGlobal (global); } } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 40581972e..c44abda2b 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -30,7 +30,8 @@ namespace CSMWorld Display_Integer, Display_Float, Display_Var, - Display_VarType + Display_GmstVarType, + Display_GlobalVarType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 270987ec1..018825831 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -96,7 +96,7 @@ namespace CSMWorld template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_VarType) {} + VarTypeColumn (ColumnBase::Display display) : Column ("Type", display) {} virtual QVariant get (const Record& record) const { @@ -125,9 +125,19 @@ namespace CSMWorld { switch (record.get().mValue.getType()) { - case ESM::VT_String: return record.get().mValue.getString().c_str(); break; - case ESM::VT_Int: return record.get().mValue.getInteger(); break; - case ESM::VT_Float: return record.get().mValue.getFloat(); break; + case ESM::VT_String: + + return record.get().mValue.getString().c_str(); break; + + case ESM::VT_Int: + case ESM::VT_Short: + case ESM::VT_Long: + + return record.get().mValue.getInteger(); break; + + case ESM::VT_Float: + + return record.get().mValue.getFloat(); break; default: return QVariant(); } @@ -145,6 +155,8 @@ namespace CSMWorld break; case ESM::VT_Int: + case ESM::VT_Short: + case ESM::VT_Long: record2.mValue.setInteger (data.toInt()); break; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d4704b0c6..bbd8667b3 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -27,12 +27,13 @@ CSMWorld::Data::Data() mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); - mGlobals.addColumn (new FloatValueColumn); + mGlobals.addColumn (new VarTypeColumn (ColumnBase::Display_GlobalVarType)); + mGlobals.addColumn (new VarValueColumn); mGmsts.addColumn (new StringIdColumn); mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); - mGmsts.addColumn (new VarTypeColumn); + mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a8faefb97..718b80728 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -35,8 +35,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; - mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType, + mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, + new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); + } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index 3ee759ef2..72cbaae42 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -85,7 +85,7 @@ void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) { { ESM::VT_None, "empty" }, { ESM::VT_Short, "short" }, - { ESM::VT_Int, "long" }, + { ESM::VT_Int, "integer" }, { ESM::VT_Long, "long" }, { ESM::VT_Float, "float" }, { ESM::VT_String, "string" }, From 2486ec6cb9edc637367bd95ff8081581a06d5f80 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Mar 2013 13:51:48 +0100 Subject: [PATCH 892/916] Material fixes (vertex colors, alpha) --- apps/openmw/mwrender/renderingmanager.cpp | 6 +- components/nifogre/ogrenifloader.cpp | 11 +- files/materials/objects.mat | 14 +-- files/materials/objects.shader | 135 ++++++---------------- files/materials/terrain.shader | 21 +--- 5 files changed, 53 insertions(+), 134 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3f559c9fd..44385e662 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -102,6 +102,7 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Set default mipmap level (NB some APIs ignore this) // Mipmap generation is currently disabled because it causes issues on Intel/AMD //TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); + TextureManager::getSingleton().setDefaultNumMipmaps(0); // Set default texture filtering options TextureFilterOptions tfo; @@ -128,7 +129,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); sh::Factory::getInstance ().setGlobalSetting ("fog", "true"); - sh::Factory::getInstance ().setGlobalSetting ("lighting", "true"); sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); sh::Factory::getInstance ().setGlobalSetting ("terrain_num_lights", Settings::Manager::getString ("num lights", "Terrain")); sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); @@ -329,8 +329,6 @@ void RenderingManager::update (float duration, bool paused) float *_playerPos = data.getPosition().pos; Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); - Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); - Ogre::Vector3 orig, dest; mPlayer->setCameraDistance(); if (!mPlayer->getPosition(orig, dest)) { @@ -353,6 +351,8 @@ void RenderingManager::update (float duration, bool paused) Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); + Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); + applyFog(world->isUnderwater (world->getPlayer().getPlayer().getCell(), cam)); if(paused) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6f7afee43..7057c83e2 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -694,21 +694,24 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String sh::MaterialInstance* instance = sh::Factory::getInstance ().createMaterialInstance (matname, "openmw_objects_base"); if(vertMode == 0 || !vertexColour) { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, alpha))); + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); } else if(vertMode == 1) { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, alpha))); + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); } else if(vertMode == 2) { instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); } else std::cerr<< "Unhandled vertex mode: "< Date: Tue, 5 Mar 2013 14:24:29 +0100 Subject: [PATCH 893/916] Avoid manually updating render targets from within frameRenderingQueued --- apps/openmw/engine.cpp | 7 +++++++ apps/openmw/engine.hpp | 1 + apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 5 +++++ apps/openmw/mwrender/renderingmanager.hpp | 1 + apps/openmw/mwrender/water.cpp | 10 ++++++++-- apps/openmw/mwrender/water.hpp | 6 +++++- apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 1 + 9 files changed, 34 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ea6e0a2f5..62e106f3f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -62,6 +62,13 @@ void OMW::Engine::setAnimationVerbose(bool animverbose) { } +bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) +{ + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) + MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame); + return true; +} + bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 572d1013e..a4acee523 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -105,6 +105,7 @@ namespace OMW void executeLocalScripts(); virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); + virtual bool frameStarted (const Ogre::FrameEvent& evt); /// Load settings from various files, returns the path to the user settings file std::string loadSettings (Settings::Manager & settings); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index eef844c76..654a59cea 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -314,6 +314,7 @@ namespace MWBase /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void stopVideo() = 0; + virtual void frameStarted (float dt) = 0; }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 44385e662..94daa8a01 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -939,4 +939,9 @@ void RenderingManager::updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, con mWater->updateEmitterPtr(old, ptr); } +void RenderingManager::frameStarted(float dt) +{ + mWater->frameStarted(dt); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e40672ada..5cea24175 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -196,6 +196,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void playVideo(const std::string& name, bool allowSkipping); void stopVideo(); + void frameStarted(float dt); protected: virtual void windowResized(Ogre::RenderWindow* rw); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 2801e6494..c8b9db7f1 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -191,7 +191,8 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mWaterTimer(0.f), mReflection(NULL), mRefraction(NULL), - mSimulation(NULL) + mSimulation(NULL), + mPlayer(0,0) { mSimulation = new RippleSimulation(mSceneMgr); @@ -371,7 +372,12 @@ void Water::update(float dt, Ogre::Vector3 player) mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - mSimulation->update(dt, Ogre::Vector2(player.x, player.y)); + mPlayer = Ogre::Vector2(player.x, player.y); +} + +void Water::frameStarted(float dt) +{ + mSimulation->update(dt, mPlayer); if (mReflection) mReflection->update(); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 633a30664..6c0323637 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -98,7 +99,7 @@ namespace MWRender { }; /// Water rendering - class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener, public sh::MaterialInstanceListener + class Water : public sh::MaterialInstanceListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; @@ -139,6 +140,8 @@ namespace MWRender { Refraction* mRefraction; RippleSimulation* mSimulation; + Ogre::Vector2 mPlayer; + public: Water (Ogre::Camera *camera, RenderingManager* rend); ~Water(); @@ -147,6 +150,7 @@ namespace MWRender { void toggle(); void update(float dt, Ogre::Vector3 player); + void frameStarted(float dt); /// adds an emitter, position will be tracked automatically using its scene node void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cddcda68b..970b339bd 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1469,4 +1469,9 @@ namespace MWWorld { mRendering->stopVideo(); } + + void World::frameStarted (float dt) + { + mRendering->frameStarted(dt); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0ae81b33a..79d036e99 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -356,6 +356,7 @@ namespace MWWorld /// \todo this does not belong here virtual void playVideo(const std::string& name, bool allowSkipping); virtual void stopVideo(); + virtual void frameStarted (float dt); }; } From ff30bef3b2cc4a7186e8d928613adf292c1aa20b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Mar 2013 14:27:05 +0100 Subject: [PATCH 894/916] Mipmap fix --- files/materials/water.mat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/materials/water.mat b/files/materials/water.mat index 3ea6a2c2b..0ec71d2df 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -37,7 +37,7 @@ material Water texture_unit normalMap { - direct_texture water_nm.png + texture water_nm.png 5 } texture_unit rippleNormalMap From 7f8d659f3cad7361b4b10ea7a23f12418d64c8b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 5 Mar 2013 17:09:20 +0100 Subject: [PATCH 895/916] Fix transparency sorting --- components/nifogre/ogrenifloader.cpp | 3 ++- extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp | 9 +++++++++ extern/shiny/Platforms/Ogre/OgrePass.cpp | 7 ------- files/materials/objects.mat | 2 ++ 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 7057c83e2..30c71023b 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -755,7 +755,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); } - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(!((alphaFlags>>13)&1) ? "on" : "off"))); + // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue(!((alphaFlags>>13)&1) ? "force" : "off"))); instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp index 9f57c7b44..4ec43fcae 100644 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp @@ -1,5 +1,7 @@ #include "OgreMaterialSerializer.hpp" +#include + namespace sh { void OgreMaterialSerializer::reset() @@ -19,6 +21,13 @@ namespace sh bool OgreMaterialSerializer::setPassProperty (const std::string& param, std::string value, Ogre::Pass* pass) { + // workaround https://ogre3d.atlassian.net/browse/OGRE-158 + if (param == "transparent_sorting" && value == "force") + { + pass->setTransparentSortingForced(true); + return true; + } + reset(); mScriptContext.section = Ogre::MSS_PASS; diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp index 8cfaae078..3ed48b96f 100644 --- a/extern/shiny/Platforms/Ogre/OgrePass.cpp +++ b/extern/shiny/Platforms/Ogre/OgrePass.cpp @@ -50,13 +50,6 @@ namespace sh return true; // handled already else if (name == "fragment_program") return true; // handled already - else if (name == "ffp_vertex_colour_ambient") - { - bool enabled = retrieveValue(value, context).get(); - // fixed-function vertex colour tracking - mPass->setVertexColourTracking(enabled ? Ogre::TVC_AMBIENT : Ogre::TVC_NONE); - return true; - } else { OgreMaterialSerializer& s = OgrePlatform::getSerializer(); diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 069a1036b..5e18a666a 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -11,6 +11,7 @@ material openmw_objects_base scene_blend default depth_write default alpha_rejection default + transparent_sorting default pass { @@ -30,6 +31,7 @@ material openmw_objects_base scene_blend $scene_blend alpha_rejection $alpha_rejection depth_write $depth_write + transparent_sorting $transparent_sorting texture_unit diffuseMap { From 9133182f2fb87b3a02a35a853b22b0f37337a249 Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 5 Mar 2013 20:25:20 +0400 Subject: [PATCH 896/916] restore loading CELL records in esmtool --- components/esm/loadcell.cpp | 12 +++++++++++- components/esm/loadcell.hpp | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 92cb7d5ce..76a48e5ec 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -79,7 +79,7 @@ void CellRef::save(ESMWriter &esm) } } -void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) +void Cell::load(ESMReader &esm, bool saveContext) { // Ignore this for now, it might mean we should delete the entire // cell? @@ -127,6 +127,16 @@ void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) esm.getHT(mNAM0); } + if (saveContext) { + mContextList.push_back(esm.getContext()); + esm.skipRecord(); + } +} + +void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) +{ + this->load(esm, false); + // preload moved references while (esm.isNextSub("MVRF")) { CellRef ref; diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 6bde9972d..7db6dbe77 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -174,7 +174,7 @@ struct Cell // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. - void load(ESMReader &esm) {}; + void load(ESMReader &esm, bool saveContext = true); void save(ESMWriter &esm); bool isExterior() const From 8b6f0e0770ef9672fc401618efa91eda52d19292 Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 5 Mar 2013 18:28:57 +0000 Subject: [PATCH 897/916] Correct orientation sign --- apps/openmw/mwrender/renderingmanager.cpp | 36 ++++++++++------------- apps/openmw/mwworld/physicssystem.cpp | 14 ++++----- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b214fd800..abc1960b8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -270,32 +270,28 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot if (!isPlayer && isActive) { - Ogre::Quaternion xr(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr(Ogre::Radian(rot.y), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr(Ogre::Radian(rot.z), Ogre::Vector3::UNIT_Z); + Ogre::Quaternion xr(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); - Ogre::Quaternion xref(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yref(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zref(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); + Ogre::Quaternion xref(Ogre::Radian(-ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yref(Ogre::Radian(-ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; - rot.x = newo.getPitch().valueRadians();// newo.x;Ogre::Quaternion:: - rot.y = newo.getYaw().valueRadians();//newo.y; - rot.z = newo.getRoll().valueRadians(); //newo.z; + Ogre::Quaternion newo = adjust ? (zr * yr * xr) * (zref*yref*xref) : zr * yr * xr; + Ogre::Radian ax,ay,az; + Ogre::Matrix3 mat; + newo.ToRotationMatrix(mat); + mat.ToEulerAnglesXYZ(ax,ay,az); + rot.x = -ax.valueRadians(); + rot.y = -ay.valueRadians(); + rot.z = -az.valueRadians(); ptr.getRefData().getBaseNode()->setOrientation(newo); } else if(isPlayer) { - rot.x = mPlayer->getPitch(); - rot.z = -mPlayer->getYaw(); - } - else if (adjust) - { - // Stored and passed in radians - float *f = ptr.getRefData().getPosition().rot; - rot.x += f[0]; - rot.y += f[1]; - rot.z += f[2]; + rot.x = -mPlayer->getPitch(); + rot.z = mPlayer->getYaw(); } return force; } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 316e57b78..c1c33cb5d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -99,9 +99,9 @@ namespace MWWorld if(!physicActor || !physicActor->getCollisionMode()) { // FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why? - return position + (Ogre::Quaternion(Ogre::Radian( refpos.rot[2]), Ogre::Vector3::UNIT_Z)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + return position + (Ogre::Quaternion(Ogre::Radian( -refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( -refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( -refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement; } @@ -115,9 +115,9 @@ namespace MWWorld Ogre::Vector3 velocity; if(!gravity) { - velocity = (Ogre::Quaternion(Ogre::Radian( refpos.rot[2]), Ogre::Vector3::UNIT_Z)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[1]), Ogre::Vector3::UNIT_Y)* - Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) * + velocity = (Ogre::Quaternion(Ogre::Radian( -refpos.rot[2]), Ogre::Vector3::UNIT_Z)* + Ogre::Quaternion(Ogre::Radian( -refpos.rot[1]), Ogre::Vector3::UNIT_Y)* + Ogre::Quaternion(Ogre::Radian( -refpos.rot[0]), Ogre::Vector3::UNIT_X)) * movement / time; } else @@ -128,7 +128,7 @@ namespace MWWorld if(trace.fraction < 1.0f && getSlope(trace.planenormal) <= sMaxSlope) onground = true; } - velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::UNIT_Z)*movement / time; + velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)*movement / time; velocity.z += physicActor->getVerticalForce(); } From d3bf3812a44eb3f40eadf197d091cbc2d61b0cc0 Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 5 Mar 2013 20:16:57 +0000 Subject: [PATCH 898/916] changing rotation order (fix some misoriented objects) --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index abc1960b8..8bad0d17e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -278,7 +278,7 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot Ogre::Quaternion yref(Ogre::Radian(-ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - Ogre::Quaternion newo = adjust ? (zr * yr * xr) * (zref*yref*xref) : zr * yr * xr; + Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; Ogre::Radian ax,ay,az; Ogre::Matrix3 mat; newo.ToRotationMatrix(mat); From c9859382bf70ef009a9a3f932e0a1ad6b2bf261d Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Wed, 6 Mar 2013 01:35:32 +0100 Subject: [PATCH 899/916] Made the launcher write the custom resolution to file, cleaned resolution parsing --- apps/launcher/graphicspage.cpp | 43 ++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 590504354..6d5b3ab09 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -190,11 +190,17 @@ void GraphicsPage::saveSettings() mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText()); - QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); - if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { - mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); - mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + if (standardRadioButton->isChecked()) { + QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); + + if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified())) { + mGraphicsSettings.setValue(QString("Video/resolution x"), resolutionRe.cap(1)); + mGraphicsSettings.setValue(QString("Video/resolution y"), resolutionRe.cap(2)); + } + } else { + mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value())); + mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value())); } } @@ -250,25 +256,26 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) for (opt_it = i->second.possibleValues.begin (); opt_it != i->second.possibleValues.end (); opt_it++, idx++) { - QString qval = QString::fromStdString(*opt_it).simplified(); - // remove extra tokens after the resolution (for example bpp, can be there or not depending on rendersystem) - QStringList tokens = qval.split(" ", QString::SkipEmptyParts); - assert (tokens.size() >= 3); + QRegExp resolutionRe(QString("(\\d+) x (\\d+)")); + QString resolution = QString::fromStdString(*opt_it).simplified(); - QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2); + if (resolutionRe.exactMatch(resolution)) { - QString aspect = getAspect(tokens.at(0).toInt(),tokens.at(2).toInt()); + int width = resolutionRe.cap(1).toInt(); + int height = resolutionRe.cap(2).toInt(); - if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { - resolutionStr.append(tr("\t(Widescreen ") + aspect + ")"); + QString aspect = getAspect(width, height); - } else if (aspect == QLatin1String("4:3")) { - resolutionStr.append(tr("\t(Standard 4:3)")); + if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { + resolution.append(tr("\t(Wide ") + aspect + ")"); + + } else if (aspect == QLatin1String("4:3")) { + resolution.append(tr("\t(Standard 4:3)")); + } + // do not add duplicate resolutions + if (!result.contains(resolution)) + result.append(resolution); } - - // do not add duplicate resolutions - if (!result.contains(resolutionStr)) - result << resolutionStr; } } From 39411eda7b663622582615d11e59c767e53dafc2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 15:11:40 +0100 Subject: [PATCH 900/916] Fix the spell buying window listing already owned spells --- apps/openmw/mwgui/spellbuyingwindow.cpp | 19 ++++++++++++++----- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 11f090494..40fcf2988 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -94,9 +94,6 @@ namespace MWGui mPtr = actor; clearSpells(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - - MWMechanics::Spells& playerSpells = MWWorld::Class::get (player).getCreatureStats (player).getSpells(); MWMechanics::Spells& merchantSpells = MWWorld::Class::get (actor).getCreatureStats (actor).getSpells(); for (MWMechanics::Spells::TIterator iter = merchantSpells.begin(); iter!=merchantSpells.end(); ++iter) @@ -107,8 +104,8 @@ namespace MWGui if (spell->mData.mType!=ESM::Spell::ST_Spell) continue; // don't try to sell diseases, curses or powers - if (std::find (playerSpells.begin(), playerSpells.end(), *iter)!=playerSpells.end()) - continue; // we have that spell already + if (playerHasSpell(iter->first)) + continue; addSpell (iter->first); } @@ -118,6 +115,18 @@ namespace MWGui mSpellsView->setCanvasSize (MyGUI::IntSize(mSpellsView->getWidth(), std::max(mSpellsView->getHeight(), mCurrentY))); } + bool SpellBuyingWindow::playerHasSpell(const std::string &id) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::Spells& playerSpells = MWWorld::Class::get (player).getCreatureStats (player).getSpells(); + for (MWMechanics::Spells::TIterator it = playerSpells.begin(); it != playerSpells.end(); ++it) + { + if (Misc::StringUtils::ciEqual(id, it->first)) + return true; + } + return false; + } + void SpellBuyingWindow::onSpellButtonClick(MyGUI::Widget* _sender) { int price = *_sender->getUserData(); diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 1d0ac28e0..c4988fff3 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -47,6 +47,8 @@ namespace MWGui void updateLabels(); virtual void onReferenceUnavailable(); + + bool playerHasSpell (const std::string& id); }; } From 268bb235908be852c016e3339af60b260036a015 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 16:58:56 +0100 Subject: [PATCH 901/916] Implemented sneaking animation --- apps/openmw/mwclass/npc.cpp | 3 +-- apps/openmw/mwinput/inputmanagerimp.cpp | 15 +++++------- apps/openmw/mwinput/inputmanagerimp.hpp | 4 ++-- apps/openmw/mwmechanics/character.cpp | 32 +++++++++++++++---------- apps/openmw/mwmechanics/character.hpp | 6 +++++ apps/openmw/mwworld/player.cpp | 7 ++++++ apps/openmw/mwworld/player.hpp | 1 + 7 files changed, 42 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c8c61e118..b1263c2e5 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -365,11 +365,10 @@ namespace MWClass fSwimRunAthleticsMult->getFloat(); moveSpeed = swimSpeed; } - else if(Npc::getStance(ptr, Run, false)) + else if(Npc::getStance(ptr, Run, false) && !Npc::getStance(ptr, Sneak, false)) moveSpeed = runSpeed; else moveSpeed = walkSpeed; - if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) moveSpeed *= 0.75f; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 69de2988c..4c10749b3 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -193,9 +193,6 @@ namespace MWInput case A_AutoMove: toggleAutoMove (); break; - case A_ToggleSneak: - /// \todo implement - break; case A_ToggleWalk: toggleWalking (); break; @@ -308,13 +305,13 @@ namespace MWInput else mPlayer.setForwardBackward (0); + mPlayer.setSneak(actionIsActive(A_Sneak)); + if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) { mPlayer.setUpDown (1); triedToMove = true; } - else if (actionIsActive(A_Crouch)) - mPlayer.setUpDown (-1); else mPlayer.setUpDown (0); @@ -364,7 +361,7 @@ namespace MWInput actionIsActive(A_MoveLeft) || actionIsActive(A_MoveRight) || actionIsActive(A_Jump) || - actionIsActive(A_Crouch) || + actionIsActive(A_Sneak) || actionIsActive(A_TogglePOV)) { resetIdleTime(); @@ -749,7 +746,7 @@ namespace MWInput defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1; defaultKeyBindings[A_Console] = OIS::KC_F2; defaultKeyBindings[A_Run] = OIS::KC_LSHIFT; - defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL; + defaultKeyBindings[A_Sneak] = OIS::KC_LCONTROL; defaultKeyBindings[A_AutoMove] = OIS::KC_Q; defaultKeyBindings[A_Jump] = OIS::KC_E; defaultKeyBindings[A_Journal] = OIS::KC_J; @@ -816,7 +813,7 @@ namespace MWInput descriptions[A_ToggleSpell] = "sReady_Magic"; descriptions[A_Console] = "sConsoleTitle"; descriptions[A_Run] = "sRun"; - descriptions[A_Crouch] = "sCrouch_Sneak"; + descriptions[A_Sneak] = "sCrouch_Sneak"; descriptions[A_AutoMove] = "sAuto_Run"; descriptions[A_Jump] = "sJump"; descriptions[A_Journal] = "sJournal"; @@ -865,7 +862,7 @@ namespace MWInput ret.push_back(A_MoveRight); ret.push_back(A_TogglePOV); ret.push_back(A_Run); - ret.push_back(A_Crouch); + ret.push_back(A_Sneak); ret.push_back(A_Activate); ret.push_back(A_ToggleWeapon); ret.push_back(A_ToggleSpell); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index d4f47723d..8bb20b7be 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -216,9 +216,9 @@ namespace MWInput A_CycleSpellRight, A_CycleWeaponLeft,//Cycling through weapons A_CycleWeaponRight, - A_ToggleSneak, //Toggles Sneak, add Push-Sneak later + A_ToggleSneak, //Toggles Sneak A_ToggleWalk, //Toggle Walking/Running - A_Crouch, + A_Sneak, A_QuickSave, A_QuickLoad, diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ae0114a35..62958db8d 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -46,6 +46,7 @@ static const struct { { CharState_Idle8, "idle8" }, { CharState_Idle9, "idle9" }, { CharState_IdleSwim, "idleswim" }, + { CharState_IdleSneak, "idlesneak" }, { CharState_WalkForward, "walkforward" }, { CharState_WalkBack, "walkback" }, @@ -67,6 +68,11 @@ static const struct { { CharState_SwimRunLeft, "swimrunleft" }, { CharState_SwimRunRight, "swimrunright" }, + { CharState_SneakForward, "sneakforward" }, + { CharState_SneakBack, "sneakback" }, + { CharState_SneakLeft, "sneakleft" }, + { CharState_SneakRight, "sneakright" }, + { CharState_Jump, "jump" }, { CharState_Death1, "death1" }, @@ -176,6 +182,7 @@ Ogre::Vector3 CharacterController::update(float duration) bool onground = world->isOnGround(mPtr); bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); + bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak); speed = cls.getSpeed(mPtr); /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except @@ -201,31 +208,30 @@ Ogre::Vector3 CharacterController::update(float duration) if(std::abs(vec.x/2.0f) > std::abs(vec.y) && speed > 0.0f) { if(vec.x > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunRight : CharState_RunRight) : - (inwater ? CharState_SwimWalkRight : CharState_WalkRight), true); + setState(inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight) + : (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight)), true); + else if(vec.x < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunLeft: CharState_RunLeft) : - (inwater ? CharState_SwimWalkLeft : CharState_WalkLeft), true); + setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) + : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); + // Apply any forward/backward movement manually movement.y += vec.y * (speed*duration); } else if(vec.y != 0.0f && speed > 0.0f) { if(vec.y > 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunForward : CharState_RunForward) : - (inwater ? CharState_SwimWalkForward : CharState_WalkForward), true); + setState(inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward) + : (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward)), true); + else if(vec.y < 0.0f) - setState(isrunning ? - (inwater ? CharState_SwimRunBack : CharState_RunBack) : - (inwater ? CharState_SwimWalkBack : CharState_WalkBack), true); + setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) + : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true); // Apply any sideways movement manually movement.x += vec.x * (speed*duration); } else if(mAnimQueue.size() == 0) - setState((inwater ? CharState_IdleSwim : CharState_Idle), true); + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); } if(mAnimation && !mSkipAnim) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2b3c50864..46f0690e7 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -25,6 +25,7 @@ enum CharacterState { CharState_Idle8, CharState_Idle9, CharState_IdleSwim, + CharState_IdleSneak, CharState_WalkForward, CharState_WalkBack, @@ -46,6 +47,11 @@ enum CharacterState { CharState_SwimRunLeft, CharState_SwimRunRight, + CharState_SneakForward, + CharState_SneakBack, + CharState_SneakLeft, + CharState_SneakRight, + CharState_Jump, /* Death states must be last! */ diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 76d44a5d7..03dd1abc7 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -86,6 +86,13 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); } + void Player::setSneak(bool sneak) + { + MWWorld::Ptr ptr = getPlayer(); + + MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Sneak, sneak); + } + MWMechanics::DrawState_ Player::getDrawState() { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 4ef4d6771..5f2fc3a08 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -67,6 +67,7 @@ namespace MWWorld void setRunState(bool run); void toggleRunning(); + void setSneak(bool sneak); }; } #endif From 66d2d3522f3fa94f73a0a23d942eb20b1405f0d5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 18:03:47 +0100 Subject: [PATCH 902/916] Race selection preview: render only the head, and focus the camera on its node --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++++++--- apps/openmw/mwrender/characterpreview.hpp | 8 ++++++++ apps/openmw/mwrender/npcanimation.cpp | 15 ++++++++++++--- apps/openmw/mwrender/npcanimation.hpp | 5 ++++- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 4a3344e22..c99e42662 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -60,7 +60,7 @@ namespace MWRender mNode = renderRoot->createChildSceneNode(); mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0); + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); mNode->setVisible (false); @@ -102,7 +102,7 @@ namespace MWRender delete mAnimation; mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0); + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); mNode->setVisible (false); @@ -161,7 +161,7 @@ namespace MWRender RaceSelectionPreview::RaceSelectionPreview() : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(), - 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 120, -35), Ogre::Vector3(0,125,0)) + 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 6, -35), Ogre::Vector3(0,125,0)) , mRef(&mBase) { mBase = *mCharacter.get()->mBase; @@ -173,6 +173,8 @@ namespace MWRender mAnimation->runAnimation(0.0f); mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); + updateCamera(); + mNode->setVisible (true); mRenderTarget->update(); mNode->setVisible (false); @@ -189,5 +191,17 @@ namespace MWRender void RaceSelectionPreview::onSetup () { mAnimation->play("idle", "start", "stop", false); + + updateCamera(); + } + + void RaceSelectionPreview::updateCamera() + { + Ogre::Vector3 scale = mNode->getScale(); + Ogre::Vector3 headOffset = mAnimation->getHeadNode()->_getDerivedPosition(); + headOffset = mNode->convertLocalToWorldPosition(headOffset); + + mCamera->setPosition(headOffset + mPosition * scale); + mCamera->lookAt(headOffset + mPosition*Ogre::Vector3(0,1,0) * scale); } } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index cf1e25069..08cbd5108 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -36,6 +36,8 @@ namespace MWRender virtual void rebuild(); protected: + virtual bool renderHeadOnly() { return false; } + Ogre::TexturePtr mTexture; Ogre::RenderTarget* mRenderTarget; Ogre::Viewport* mViewport; @@ -82,6 +84,12 @@ namespace MWRender ESM::NPC mBase; MWWorld::LiveCellRef mRef; + protected: + + virtual bool renderHeadOnly() { return true; } + + void updateCamera(); + public: RaceSelectionPreview(); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a7d5c22af..9da70beb4 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -54,7 +54,7 @@ NpcAnimation::~NpcAnimation() } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly) : Animation(ptr), mStateID(-1), mTimeToChange(0), @@ -70,7 +70,8 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mPants(inv.end()), mGloveL(inv.end()), mGloveR(inv.end()), - mSkirtIter(inv.end()) + mSkirtIter(inv.end()), + mHeadOnly(headOnly) { mNpc = mPtr.get()->mBase; @@ -215,7 +216,7 @@ void NpcAnimation::updateParts(bool forceupdate) if(!forceupdate) return; - for(size_t i = 0;i < slotlistsize;i++) + for(size_t i = 0;i < slotlistsize && !mHeadOnly;i++) { MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); @@ -252,6 +253,9 @@ void NpcAnimation::updateParts(bool forceupdate) if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); + if (mHeadOnly) + return; + static const struct { ESM::PartReferenceType type; const char name[2][12]; @@ -449,4 +453,9 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorgetSkeleton()->getBone("Bip01 Head"); +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index aed4868bd..5da4afef8 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -39,6 +39,7 @@ private: std::string mHeadModel; std::string mHairModel; std::string mBodyPrefix; + bool mHeadOnly; float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; @@ -73,11 +74,13 @@ private: public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& inv, int visibilityFlags); + MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly=false); virtual ~NpcAnimation(); virtual Ogre::Vector3 runAnimation(float timepassed); + Ogre::Node* getHeadNode(); + void forceUpdate() { updateParts(true); } }; From 5938e19362a2acc7d6897be32724fda00c4b9398 Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 17:31:57 +0000 Subject: [PATCH 903/916] Clean up --- apps/openmw/mwrender/renderingmanager.cpp | 4 +++- libs/openengine/bullet/physic.cpp | 23 +++++++---------------- libs/openengine/bullet/physic.hpp | 8 ++++++++ libs/openengine/bullet/trace.cpp | 20 +------------------- 4 files changed, 19 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 8bad0d17e..1cd7c7a3e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -279,13 +279,15 @@ bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; - Ogre::Radian ax,ay,az; + Ogre::Matrix3 mat; newo.ToRotationMatrix(mat); + Ogre::Radian ax,ay,az; mat.ToEulerAnglesXYZ(ax,ay,az); rot.x = -ax.valueRadians(); rot.y = -ay.valueRadians(); rot.z = -az.valueRadians(); + ptr.getRefData().getBaseNode()->setOrientation(newo); } else if(isPlayer) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 677d75f33..435ceef23 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -13,18 +13,9 @@ #include #include -#define BIT(x) (1<<(x)) - namespace OEngine { namespace Physic { - enum collisiontypes { - COL_NOTHING = 0, //addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL); + dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); } void PhysicEngine::removeHeightField(int x, int y) @@ -401,11 +392,11 @@ namespace Physic return; if(body->mCollide) { - dynamicsWorld->addRigidBody(body,COL_WORLD,COL_WORLD|COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL); + dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); } else { - dynamicsWorld->addRigidBody(body,COL_RAYCASTING,COL_RAYCASTING|COL_WORLD); + dynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_World); } body->setActivationState(DISABLE_DEACTIVATION); if(addToMap){ @@ -539,7 +530,7 @@ namespace Physic float d1 = 10000.; btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterMask = COL_WORLD|COL_RAYCASTING; + resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_Raycasting; dynamicsWorld->rayTest(from, to, resultCallback1); if (resultCallback1.hasHit()) { @@ -549,7 +540,7 @@ namespace Physic } btCollisionWorld::ClosestRayResultCallback resultCallback2(from, to); - resultCallback2.m_collisionFilterMask = COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL; + resultCallback2.m_collisionFilterMask = CollisionType_ActorInternal|CollisionType_ActorExternal; dynamicsWorld->rayTest(from, to, resultCallback2); float d2 = 10000.; if (resultCallback2.hasHit()) @@ -568,12 +559,12 @@ namespace Physic std::vector< std::pair > PhysicEngine::rayTest2(btVector3& from, btVector3& to) { MyRayResultCallback resultCallback1; - resultCallback1.m_collisionFilterMask = COL_WORLD|COL_RAYCASTING; + resultCallback1.m_collisionFilterMask = CollisionType_World|CollisionType_Raycasting; dynamicsWorld->rayTest(from, to, resultCallback1); std::vector< std::pair > results = resultCallback1.results; MyRayResultCallback resultCallback2; - resultCallback2.m_collisionFilterMask = COL_ACTOR_INTERNAL|COL_ACTOR_EXTERNAL; + resultCallback2.m_collisionFilterMask = CollisionType_ActorInternal|CollisionType_ActorExternal; dynamicsWorld->rayTest(from, to, resultCallback2); std::vector< std::pair > actorResults = resultCallback2.results; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index e579e3546..97fbbcea4 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -43,6 +43,14 @@ namespace Physic class PhysicEngine; class RigidBody; + enum CollisionType { + CollisionType_Nothing = 0, //dynamicsWorld->convexSweepTest(&newshape, from, to, newTraceCallback); From 642653d10e12eeeb6cef02a63f62480687499bb6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 6 Mar 2013 19:57:00 +0100 Subject: [PATCH 904/916] World constructor fixes --- apps/openmw/mwworld/worldimp.cpp | 7 +++---- apps/openmw/mwworld/worldimp.hpp | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f9e4a743f..7d3efe3e8 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -178,10 +178,11 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& master, const std::vector& plugins, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - ToUTF8::Utf8Encoder* encoder, std::map fallbackMap, int mActivationDistanceOverride) + ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), - mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride) + mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride), + mFallback (fallbackMap) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); @@ -247,8 +248,6 @@ namespace MWWorld mWorldScene = new Scene(*mRendering, mPhysics); - setFallbackValues(fallbackMap); - lastTick = mTimer.getMilliseconds(); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 79d036e99..47088aa62 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -92,7 +92,7 @@ namespace MWWorld bool moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return true if the active cell (cell player is in) changed - + Ptr copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos); void updateWindowManager (); @@ -116,7 +116,7 @@ namespace MWWorld const Files::Collections& fileCollections, const std::vector& master, const std::vector& plugins, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, bool newGame, - ToUTF8::Utf8Encoder* encoder, std::map fallbackMap, int mActivationDistanceOverride); + ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride); virtual ~World(); @@ -174,11 +174,11 @@ namespace MWWorld virtual char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name. - + virtual std::vector getGlobals () const; - + virtual std::string getCurrentCellName () const; - + virtual void removeRefScript (MWWorld::RefData *ref); //< Remove the script attached to ref from mLocalScripts From f7d8f6456f13907502db90bf0540b20826886c1c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 20:45:11 +0100 Subject: [PATCH 905/916] Stats should never go below 0 --- apps/openmw/mwmechanics/stat.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index d576020c5..e1bb1994c 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -28,7 +28,7 @@ namespace MWMechanics const T& getModified() const { - return mModified; + return std::max(static_cast(0), mModified); } T getModifier() const From 8be9627c8d62fa81cabd814e8382f9a55338301c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 6 Mar 2013 21:26:41 +0100 Subject: [PATCH 906/916] Fix method signatures --- apps/openmw/mwmechanics/stat.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index e1bb1994c..e9b7f4385 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -26,7 +26,7 @@ namespace MWMechanics return mBase; } - const T& getModified() const + T getModified() const { return std::max(static_cast(0), mModified); } @@ -108,7 +108,7 @@ namespace MWMechanics return mStatic.getBase(); } - const T& getModified() const + T getModified() const { return mStatic.getModified(); } From 7504ae675b44c4ebea2509d8ef3e8381200111d3 Mon Sep 17 00:00:00 2001 From: Pieter van der Kloet Date: Thu, 7 Mar 2013 03:00:59 +0100 Subject: [PATCH 907/916] Implemented a file dialog for the editor using launcher .ui --- apps/launcher/CMakeLists.txt | 16 +- apps/launcher/datafilespage.cpp | 60 +--- apps/launcher/resources.qrc | 21 -- apps/opencs/CMakeLists.txt | 6 +- apps/opencs/editor.cpp | 101 ++++-- apps/opencs/editor.hpp | 15 +- apps/opencs/view/doc/filedialog.cpp | 272 ++++++++++++++++ apps/opencs/view/doc/filedialog.hpp | 66 ++++ components/CMakeLists.txt | 2 +- components/fileorderlist/datafileslist.cpp | 293 ------------------ components/fileorderlist/datafileslist.hpp | 75 ----- .../fileorderlist/model/datafilesmodel.cpp | 1 + .../fileorderlist/model/datafilesmodel.hpp | 3 + .../model/pluginsproxymodel.cpp | 0 .../model/pluginsproxymodel.hpp | 0 .../launcher}/icons/tango/document-new.png | Bin .../launcher}/icons/tango/edit-copy.png | Bin .../launcher}/icons/tango/edit-delete.png | Bin .../launcher}/icons/tango/go-bottom.png | Bin .../launcher}/icons/tango/go-down.png | Bin .../launcher}/icons/tango/go-top.png | Bin .../launcher}/icons/tango/go-up.png | Bin .../launcher}/icons/tango/index.theme | 0 .../launcher}/icons/tango/video-display.png | Bin .../launcher}/images/clear.png | Bin .../launcher}/images/down.png | Bin .../launcher}/images/openmw-header.png | Bin .../launcher}/images/openmw-plugin.png | Bin .../launcher}/images/openmw.ico | Bin .../launcher}/images/openmw.png | Bin .../launcher}/images/playpage-background.png | Bin files/launcher/launcher.qrc | 21 ++ {apps/launcher => files}/ui/datafilespage.ui | 2 +- {apps/launcher => files}/ui/graphicspage.ui | 0 {apps/launcher => files}/ui/mainwindow.ui | 0 {apps/launcher => files}/ui/playpage.ui | 0 36 files changed, 464 insertions(+), 490 deletions(-) delete mode 100644 apps/launcher/resources.qrc create mode 100644 apps/opencs/view/doc/filedialog.cpp create mode 100644 apps/opencs/view/doc/filedialog.hpp delete mode 100644 components/fileorderlist/datafileslist.cpp delete mode 100644 components/fileorderlist/datafileslist.hpp rename {apps/launcher => components/fileorderlist}/model/pluginsproxymodel.cpp (100%) rename {apps/launcher => components/fileorderlist}/model/pluginsproxymodel.hpp (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/document-new.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/edit-copy.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/edit-delete.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/go-bottom.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/go-down.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/go-top.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/go-up.png (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/index.theme (100%) rename {apps/launcher/resources => files/launcher}/icons/tango/video-display.png (100%) rename {apps/launcher/resources => files/launcher}/images/clear.png (100%) rename {apps/launcher/resources => files/launcher}/images/down.png (100%) rename {apps/launcher/resources => files/launcher}/images/openmw-header.png (100%) rename {apps/launcher/resources => files/launcher}/images/openmw-plugin.png (100%) rename {apps/launcher/resources => files/launcher}/images/openmw.ico (100%) rename {apps/launcher/resources => files/launcher}/images/openmw.png (100%) rename {apps/launcher/resources => files/launcher}/images/playpage-background.png (100%) create mode 100644 files/launcher/launcher.qrc rename {apps/launcher => files}/ui/datafilespage.ui (98%) rename {apps/launcher => files}/ui/graphicspage.ui (100%) rename {apps/launcher => files}/ui/mainwindow.ui (100%) rename {apps/launcher => files}/ui/playpage.ui (100%) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index a1c228945..a63898c0e 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -5,8 +5,6 @@ set(LAUNCHER maindialog.cpp playpage.cpp - model/pluginsproxymodel.cpp - settings/gamesettings.cpp settings/graphicssettings.cpp settings/launchersettings.cpp @@ -23,8 +21,6 @@ set(LAUNCHER_HEADER maindialog.hpp playpage.hpp - model/pluginsproxymodel.hpp - settings/gamesettings.hpp settings/graphicssettings.hpp settings/launchersettings.hpp @@ -42,17 +38,15 @@ set(LAUNCHER_HEADER_MOC maindialog.hpp playpage.hpp - model/pluginsproxymodel.hpp - utils/checkablemessagebox.hpp utils/textinputdialog.hpp ) set(LAUNCHER_UI - ui/datafilespage.ui - ui/graphicspage.ui - ui/mainwindow.ui - ui/playpage.ui + ../../files/ui/datafilespage.ui + ../../files/ui/graphicspage.ui + ../../files/ui/mainwindow.ui + ../../files/ui/playpage.ui ) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) @@ -66,7 +60,7 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -QT4_ADD_RESOURCES(RCC_SRCS resources.qrc) +QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc) QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 069cdd9ac..90cdd2942 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -2,25 +2,21 @@ #include -#include #include #include +#include #include #include #include #include -#include "model/pluginsproxymodel.hpp" - #include "settings/gamesettings.hpp" #include "settings/launchersettings.hpp" #include "utils/textinputdialog.hpp" -using namespace ESM; -using namespace std; //sort QModelIndexList ascending bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2) @@ -100,60 +96,6 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, GameSettings &gam splitter->setSizes(sizeList); -// // Filter toolbar -// QLabel *filterLabel = new QLabel(tr("&Filter:"), this); -// LineEdit *filterLineEdit = new LineEdit(this); -// filterLabel->setBuddy(filterLineEdit); - -// QToolBar *filterToolBar = new QToolBar(this); -// filterToolBar->setMovable(false); - -// // Create a container widget and a layout to get the spacer to work -// QWidget *filterWidget = new QWidget(this); -// QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget); -// QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - -// filterLayout->addItem(hSpacer1); -// filterLayout->addWidget(filterLabel); -// filterLayout->addWidget(filterLineEdit); - -// filterToolBar->addWidget(filterWidget); - - - -// // Add both tables to a splitter -// mSplitter = new QSplitter(this); -// mSplitter->setOrientation(Qt::Horizontal); -// mSplitter->setChildrenCollapsible(false); // Don't allow the widgets to be hidden -// mSplitter->addWidget(mastersTable); -// mSplitter->addWidget(pluginsTable); - - - -// - -// // Bottom part with profile options -// QLabel *profileLabel = new QLabel(tr("Current Profile: "), this); - -// profilesComboBox = new ProfilesComboBox(this); -// profilesComboBox->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum)); -// profilesComboBox->setInsertPolicy(QComboBox::NoInsert); -// profilesComboBox->setDuplicatesEnabled(false); -// profilesComboBox->setEditEnabled(false); - -// mProfileToolBar = new QToolBar(this); -// mProfileToolBar->setMovable(false); -// mProfileToolBar->setIconSize(QSize(16, 16)); - -// mProfileToolBar->addWidget(profileLabel); -// mProfileToolBar->addWidget(profilesComboBox); - -// QVBoxLayout *pageLayout = new QVBoxLayout(this); - -// pageLayout->addWidget(filterToolBar); -// pageLayout->addWidget(mSplitter); -// pageLayout->addWidget(mProfileToolBar); - // Create a dialog for the new profile name input mNewProfileDialog = new TextInputDialog(tr("New Profile"), tr("Profile name:"), this); diff --git a/apps/launcher/resources.qrc b/apps/launcher/resources.qrc deleted file mode 100644 index 2b56f80fd..000000000 --- a/apps/launcher/resources.qrc +++ /dev/null @@ -1,21 +0,0 @@ - - - resources/images/clear.png - resources/images/down.png - resources/images/openmw.png - resources/images/openmw-plugin.png - resources/images/openmw-header.png - resources/images/playpage-background.png - - - resources/icons/tango/index.theme - resources/icons/tango/video-display.png - resources/icons/tango/document-new.png - resources/icons/tango/edit-copy.png - resources/icons/tango/edit-delete.png - resources/icons/tango/go-bottom.png - resources/icons/tango/go-down.png - resources/icons/tango/go-top.png - resources/icons/tango/go-up.png - - diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d5d389a14..0071dd1fc 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -41,7 +41,7 @@ opencs_units_noqt (model/tools opencs_units (view/doc - viewmanager view operations operation subview startup opendialog + viewmanager view operations operation subview startup filedialog ) @@ -76,6 +76,10 @@ set (OPENCS_US ) set (OPENCS_RES ../../files/opencs/resources.qrc + ../../files/launcher/launcher.qrc + ) + +set (OPENCS_UI ../../files/ui/datafilespage.ui ) source_group (opencs FILES ${OPENCS_SRC} ${OPENCS_HDR}) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e2df365a2..5966d089e 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,14 +1,12 @@ #include "editor.hpp" -#include - #include #include "model/doc/document.hpp" #include "model/world/data.hpp" -CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) +CS::Editor::Editor() : mViewManager (mDocumentManager) { connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); @@ -16,42 +14,99 @@ CS::Editor::Editor() : mViewManager (mDocumentManager), mNewDocumentIndex (0) connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); - connect (&mOpenDialog, SIGNAL(accepted()), this, SLOT(openFiles())); + connect (&mFileDialog, SIGNAL(openFiles()), this, SLOT(openFiles())); + connect (&mFileDialog, SIGNAL(createNewFile()), this, SLOT(createNewFile())); + + setupDataFiles(); +} + +void CS::Editor::setupDataFiles() +{ + boost::program_options::variables_map variables; + boost::program_options::options_description desc; + + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) + ("data-local", boost::program_options::value()->default_value("")) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("encoding", boost::program_options::value()->default_value("win1252")); + + boost::program_options::notify(variables); + + mCfgMgr.readConfiguration(variables, desc); + + Files::PathContainer mDataDirs, mDataLocal; + if (!variables["data"].empty()) { + mDataDirs = Files::PathContainer(variables["data"].as()); + } + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + mDataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + // Set the charset for reading the esm/esp files + QString encoding = QString::fromStdString(variables["encoding"].as()); + mFileDialog.setEncoding(encoding); + + Files::PathContainer dataDirs; + dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end()); + dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end()); + + for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) + { + QString path = QString::fromStdString(iter->string()); + mFileDialog.addFiles(path); + } } void CS::Editor::createDocument() { mStartup.hide(); - /// \todo open the ESX picker instead - - std::ostringstream stream; - - stream << "NewDocument" << (++mNewDocumentIndex); - - std::vector files; - files.push_back (stream.str()); - - CSMDoc::Document *document = mDocumentManager.addDocument (files, true); - - mViewManager.addView (document); + mFileDialog.newFile(); } void CS::Editor::loadDocument() { mStartup.hide(); - mOpenDialog.show(); - mOpenDialog.raise(); - mOpenDialog.activateWindow(); + + mFileDialog.openFile(); } void CS::Editor::openFiles() { - std::vector paths; - mOpenDialog.getFileList(paths); - CSMDoc::Document *document = mDocumentManager.addDocument(paths, false); + std::vector files; + QStringList paths = mFileDialog.checkedItemsPaths(); + + foreach (const QString &path, paths) { + files.push_back(path.toStdString()); + } + + CSMDoc::Document *document = mDocumentManager.addDocument(files, false); mViewManager.addView (document); + mFileDialog.hide(); +} + +void CS::Editor::createNewFile() +{ + std::vector files; + QStringList paths = mFileDialog.checkedItemsPaths(); + + foreach (const QString &path, paths) { + files.push_back(path.toStdString()); + } + + files.push_back(mFileDialog.fileName().toStdString()); + + CSMDoc::Document *document = mDocumentManager.addDocument (files, true); + + mViewManager.addView (document); + mFileDialog.hide(); } int CS::Editor::run() @@ -59,4 +114,4 @@ int CS::Editor::run() mStartup.show(); return QApplication::exec(); -} \ No newline at end of file +} diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 024475bf0..c242a17ea 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -3,11 +3,13 @@ #include +#include + #include "model/doc/documentmanager.hpp" #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" -#include "view/doc/opendialog.hpp" +#include "view/doc/filedialog.hpp" namespace CS { @@ -15,12 +17,14 @@ namespace CS { Q_OBJECT - int mNewDocumentIndex; ///< \todo remove when the proper new document dialogue is implemented. - CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; - OpenDialog mOpenDialog; + FileDialog mFileDialog; + + Files::ConfigurationManager mCfgMgr; + + void setupDataFiles(); // not implemented Editor (const Editor&); @@ -39,7 +43,8 @@ namespace CS void loadDocument(); void openFiles(); + void createNewFile(); }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp new file mode 100644 index 000000000..f956317a7 --- /dev/null +++ b/apps/opencs/view/doc/filedialog.cpp @@ -0,0 +1,272 @@ +#include "filedialog.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +FileDialog::FileDialog(QWidget *parent) : + QDialog(parent) +{ + setupUi(this); + + // Models + mDataFilesModel = new DataFilesModel(this); + + mMastersProxyModel = new QSortFilterProxyModel(); + mMastersProxyModel->setFilterRegExp(QString("^.*\\.esm")); + mMastersProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mMastersProxyModel->setSourceModel(mDataFilesModel); + + mPluginsProxyModel = new PluginsProxyModel(); + mPluginsProxyModel->setFilterRegExp(QString("^.*\\.esp")); + mPluginsProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + mPluginsProxyModel->setSourceModel(mDataFilesModel); + + mFilterProxyModel = new QSortFilterProxyModel(); + mFilterProxyModel->setDynamicSortFilter(true); + mFilterProxyModel->setSourceModel(mPluginsProxyModel); + + QCheckBox checkBox; + unsigned int height = checkBox.sizeHint().height() + 4; + + mastersTable->setModel(mMastersProxyModel); + mastersTable->setObjectName("MastersTable"); + mastersTable->setContextMenuPolicy(Qt::CustomContextMenu); + mastersTable->setSortingEnabled(false); + mastersTable->setSelectionBehavior(QAbstractItemView::SelectRows); + mastersTable->setSelectionMode(QAbstractItemView::ExtendedSelection); + mastersTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + mastersTable->setAlternatingRowColors(true); + mastersTable->horizontalHeader()->setStretchLastSection(true); + + // Set the row height to the size of the checkboxes + mastersTable->verticalHeader()->setDefaultSectionSize(height); + mastersTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + mastersTable->verticalHeader()->hide(); + + pluginsTable->setModel(mFilterProxyModel); + pluginsTable->setObjectName("PluginsTable"); + pluginsTable->setContextMenuPolicy(Qt::CustomContextMenu); + pluginsTable->setSortingEnabled(false); + pluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows); + pluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection); + pluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers); + pluginsTable->setAlternatingRowColors(true); + pluginsTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); + pluginsTable->horizontalHeader()->setStretchLastSection(true); + + pluginsTable->verticalHeader()->setDefaultSectionSize(height); + pluginsTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); + + // Hide the profile elements + profileLabel->hide(); + profilesComboBox->hide(); + newProfileButton->hide(); + deleteProfileButton->hide(); + + // Add some extra widgets + QHBoxLayout *nameLayout = new QHBoxLayout(); + QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + + mNameLabel = new QLabel(tr("File Name:"), this); + + QRegExpValidator *validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$")); + mNameLineEdit = new LineEdit(this); + mNameLineEdit->setValidator(validator); + + nameLayout->addSpacerItem(spacer); + nameLayout->addWidget(mNameLabel); + nameLayout->addWidget(mNameLineEdit); + + mButtonBox = new QDialogButtonBox(this); + + mCreateButton = new QPushButton(tr("Create"), this); + mCreateButton->setEnabled(false); + + verticalLayout->addLayout(nameLayout); + verticalLayout->addWidget(mButtonBox); + + // Set sizes + QList sizeList; + sizeList << 175; + sizeList << 200; + + splitter->setSizes(sizeList); + + resize(600, 400); + + connect(mDataFilesModel, SIGNAL(layoutChanged()), this, SLOT(updateViews())); + connect(mDataFilesModel, SIGNAL(checkedItemsChanged(QStringList)), this, SLOT(updateOpenButton(QStringList))); + connect(mNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateCreateButton(QString))); + + connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); + + connect(pluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + connect(mastersTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); + + connect(mCreateButton, SIGNAL(clicked()), this, SLOT(createButtonClicked())); + + connect(mButtonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); +} + +void FileDialog::updateViews() +{ + // Ensure the columns are hidden because sort() re-enables them + mastersTable->setColumnHidden(1, true); + mastersTable->setColumnHidden(3, true); + mastersTable->setColumnHidden(4, true); + mastersTable->setColumnHidden(5, true); + mastersTable->setColumnHidden(6, true); + mastersTable->setColumnHidden(7, true); + mastersTable->setColumnHidden(8, true); + mastersTable->resizeColumnsToContents(); + + pluginsTable->setColumnHidden(1, true); + pluginsTable->setColumnHidden(3, true); + pluginsTable->setColumnHidden(4, true); + pluginsTable->setColumnHidden(5, true); + pluginsTable->setColumnHidden(6, true); + pluginsTable->setColumnHidden(7, true); + pluginsTable->setColumnHidden(8, true); + pluginsTable->resizeColumnsToContents(); + +} + +void FileDialog::updateOpenButton(const QStringList &items) +{ + QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open); + + if (!openButton) + return; + + openButton->setEnabled(!items.isEmpty()); +} + +void FileDialog::updateCreateButton(const QString &name) +{ + if (!mCreateButton->isVisible()) + return; + + mCreateButton->setEnabled(!name.isEmpty()); +} + +void FileDialog::filterChanged(const QString &filter) +{ + QRegExp filterRe(filter, Qt::CaseInsensitive, QRegExp::FixedString); + mFilterProxyModel->setFilterRegExp(filterRe); +} + +void FileDialog::addFiles(const QString &path) +{ + mDataFilesModel->addFiles(path); + mDataFilesModel->sort(3); // Sort by date accessed +} + +void FileDialog::setEncoding(const QString &encoding) +{ + mDataFilesModel->setEncoding(encoding); +} + +void FileDialog::setCheckState(QModelIndex index) +{ + if (!index.isValid()) + return; + + QObject *object = QObject::sender(); + + // Not a signal-slot call + if (!object) + return; + + + if (object->objectName() == QLatin1String("PluginsTable")) { + QModelIndex sourceIndex = mPluginsProxyModel->mapToSource( + mFilterProxyModel->mapToSource(index)); + + if (sourceIndex.isValid()) { + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); + } + } + + if (object->objectName() == QLatin1String("MastersTable")) { + QModelIndex sourceIndex = mMastersProxyModel->mapToSource(index); + + if (sourceIndex.isValid()) { + (mDataFilesModel->checkState(sourceIndex) == Qt::Checked) + ? mDataFilesModel->setCheckState(sourceIndex, Qt::Unchecked) + : mDataFilesModel->setCheckState(sourceIndex, Qt::Checked); + } + } + + return; +} + +QStringList FileDialog::checkedItemsPaths() +{ + return mDataFilesModel->checkedItemsPaths(); +} + +QString FileDialog::fileName() +{ + return mNameLineEdit->text(); +} + +void FileDialog::openFile() +{ + setWindowTitle(tr("Open")); + + mNameLabel->hide(); + mNameLineEdit->hide(); + mCreateButton->hide(); + + mButtonBox->removeButton(mCreateButton); + mButtonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Open); + QPushButton *openButton = mButtonBox->button(QDialogButtonBox::Open); + openButton->setEnabled(false); + + show(); + raise(); + activateWindow(); +} + +void FileDialog::newFile() +{ + setWindowTitle(tr("New")); + + mNameLabel->show(); + mNameLineEdit->clear(); + mNameLineEdit->show(); + mCreateButton->show(); + + mButtonBox->setStandardButtons(QDialogButtonBox::Cancel); + mButtonBox->addButton(mCreateButton, QDialogButtonBox::ActionRole); + + show(); + raise(); + activateWindow(); +} + +void FileDialog::accept() +{ + emit openFiles(); +} + +void FileDialog::createButtonClicked() +{ + emit createNewFile(); +} diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp new file mode 100644 index 000000000..b21618d5d --- /dev/null +++ b/apps/opencs/view/doc/filedialog.hpp @@ -0,0 +1,66 @@ +#ifndef FILEDIALOG_HPP +#define FILEDIALOG_HPP + +#include +#include + +#include "ui_datafilespage.h" + +class QDialogButtonBox; +class QSortFilterProxyModel; +class QAbstractItemModel; +class QPushButton; +class QStringList; +class QString; +class QMenu; + +class DataFilesModel; +class PluginsProxyModel; + +class FileDialog : public QDialog, private Ui::DataFilesPage +{ + Q_OBJECT +public: + explicit FileDialog(QWidget *parent = 0); + void addFiles(const QString &path); + void setEncoding(const QString &encoding); + + void openFile(); + void newFile(); + void accepted(); + + QStringList checkedItemsPaths(); + QString fileName(); + +signals: + void openFiles(); + void createNewFile(); + +public slots: + void accept(); + +private slots: + void updateViews(); + void updateOpenButton(const QStringList &items); + void updateCreateButton(const QString &name); + void setCheckState(QModelIndex index); + + void filterChanged(const QString &filter); + + void createButtonClicked(); + +private: + QLabel *mNameLabel; + LineEdit *mNameLineEdit; + + QPushButton *mCreateButton; + QDialogButtonBox *mButtonBox; + + DataFilesModel *mDataFilesModel; + + PluginsProxyModel *mPluginsProxyModel; + QSortFilterProxyModel *mMastersProxyModel; + QSortFilterProxyModel *mFilterProxyModel; +}; + +#endif // FILEDIALOG_HPP diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7c52ab12c..a4b194fab 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -70,7 +70,7 @@ find_package(Qt4 COMPONENTS QtCore QtGui) if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (fileorderlist - datafileslist model/modelitem model/datafilesmodel model/esm/esmfile + model/modelitem model/datafilesmodel model/pluginsproxymodel model/esm/esmfile utils/profilescombobox utils/comboboxlineedit utils/lineedit utils/naturalsort ) diff --git a/components/fileorderlist/datafileslist.cpp b/components/fileorderlist/datafileslist.cpp deleted file mode 100644 index 9fe8d0fea..000000000 --- a/components/fileorderlist/datafileslist.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include - -#include -#include - -#include "model/datafilesmodel.hpp" -#include "model/esm/esmfile.hpp" - -#include "utils/lineedit.hpp" - -#include "datafileslist.hpp" - -#include -/** - * Workaround for problems with whitespaces in paths in older versions of Boost library - */ -#if (BOOST_VERSION <= 104600) -namespace boost -{ - - template<> - inline boost::filesystem::path lexical_cast(const std::string& arg) - { - return boost::filesystem::path(arg); - } - -} /* namespace boost */ -#endif /* (BOOST_VERSION <= 104600) */ - -using namespace ESM; -using namespace std; - -//sort QModelIndexList ascending -bool rowGreaterThan(const QModelIndex &index1, const QModelIndex &index2) -{ - return index1.row() >= index2.row(); -} - -//sort QModelIndexList descending -bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) -{ - return index1.row() <= index2.row(); -} - -DataFilesList::DataFilesList(Files::ConfigurationManager &cfg, QWidget *parent) - : QWidget(parent) - , mCfgMgr(cfg) -{ - // Model - mFilesModel = new DataFilesModel(this); - - mFilesProxyModel = new QSortFilterProxyModel(); - mFilesProxyModel->setDynamicSortFilter(true); - mFilesProxyModel->setSourceModel(mFilesModel); - - // Filter toolbar - QLabel *filterLabel = new QLabel(tr("&Filter:"), this); - LineEdit *filterLineEdit = new LineEdit(this); - filterLabel->setBuddy(filterLineEdit); - - QToolBar *filterToolBar = new QToolBar(this); - filterToolBar->setMovable(false); - - // Create a container widget and a layout to get the spacer to work - QWidget *filterWidget = new QWidget(this); - QHBoxLayout *filterLayout = new QHBoxLayout(filterWidget); - QSpacerItem *hSpacer1 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - - filterLayout->addItem(hSpacer1); - filterLayout->addWidget(filterLabel); - filterLayout->addWidget(filterLineEdit); - - filterToolBar->addWidget(filterWidget); - - QCheckBox checkBox; - unsigned int height = checkBox.sizeHint().height() + 4; - - mFilesTable = new QTableView(this); - mFilesTable->setModel(mFilesProxyModel); - mFilesTable->setObjectName("PluginsTable"); - mFilesTable->setContextMenuPolicy(Qt::CustomContextMenu); - mFilesTable->setSelectionBehavior(QAbstractItemView::SelectRows); - mFilesTable->setSelectionMode(QAbstractItemView::SingleSelection); - mFilesTable->setEditTriggers(QAbstractItemView::NoEditTriggers); - mFilesTable->setAlternatingRowColors(true); - mFilesTable->setVerticalScrollMode(QAbstractItemView::ScrollPerItem); - mFilesTable->horizontalHeader()->setStretchLastSection(true); - mFilesTable->horizontalHeader()->hide(); - - mFilesTable->verticalHeader()->setDefaultSectionSize(height); - mFilesTable->verticalHeader()->setResizeMode(QHeaderView::Fixed); - mFilesTable->setColumnHidden(1, true); - mFilesTable->setColumnHidden(2, true); - mFilesTable->setColumnHidden(3, true); - mFilesTable->setColumnHidden(4, true); - mFilesTable->setColumnHidden(5, true); - mFilesTable->setColumnHidden(6, true); - mFilesTable->setColumnHidden(7, true); - mFilesTable->setColumnHidden(8, true); - - QVBoxLayout *pageLayout = new QVBoxLayout(this); - - pageLayout->addWidget(filterToolBar); - pageLayout->addWidget(mFilesTable); - - connect(mFilesTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex))); - - connect(mFilesModel, SIGNAL(checkedItemsChanged(QStringList,QStringList)), mFilesModel, SLOT(slotcheckedItemsChanged(QStringList,QStringList))); - - connect(filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterChanged(QString))); - - connect(mFilesTable, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); - - createActions(); -} - -void DataFilesList::createActions() -{ - // Refresh the plugins - QAction *refreshAction = new QAction(tr("Refresh"), this); - refreshAction->setShortcut(QKeySequence(tr("F5"))); - connect(refreshAction, SIGNAL(triggered()), this, SLOT(refresh())); - - // Context menu actions - mCheckAction = new QAction(tr("Check selected"), this); - connect(mCheckAction, SIGNAL(triggered()), this, SLOT(check())); - - mUncheckAction = new QAction(tr("Uncheck selected"), this); - connect(mUncheckAction, SIGNAL(triggered()), this, SLOT(uncheck())); - - // Context menu for the plugins table - mContextMenu = new QMenu(this); - - mContextMenu->addAction(mCheckAction); - mContextMenu->addAction(mUncheckAction); - -} - -bool DataFilesList::setupDataFiles(Files::PathContainer dataDirs, const QString encoding) -{ - // Set the charset for reading the esm/esp files - if (!encoding.isEmpty() && encoding != QLatin1String("win1252")) { - mFilesModel->setEncoding(encoding); - } - - // Add the paths to the respective models - for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { - QString path = QString::fromStdString(it->string()); - path.remove(QChar('\"')); - mFilesModel->addFiles(path); - } - - mFilesModel->sort(0); -// mMastersTable->sortByColumn(3, Qt::AscendingOrder); -// mPluginsTable->sortByColumn(3, Qt::AscendingOrder); - - return true; -} - -void DataFilesList::selectedFiles(std::vector& paths) -{ - QStringList pluginPaths = mFilesModel->checkedItemsPaths(); - foreach (const QString &path, pluginPaths) - { - paths.push_back(path.toStdString()); - } -} - -void DataFilesList::check() -{ - // Check the current selection - if (!mFilesTable->selectionModel()->hasSelection()) { - return; - } - - QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); - - //sort selection ascending because selectedIndexes returns an unsorted list - //qSort(indexes.begin(), indexes.end(), rowSmallerThan); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - mFilesModel->setCheckState(index, Qt::Checked); - } -} - -void DataFilesList::uncheck() -{ - // uncheck the current selection - if (!mFilesTable->selectionModel()->hasSelection()) { - return; - } - - QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); - - //sort selection ascending because selectedIndexes returns an unsorted list - //qSort(indexes.begin(), indexes.end(), rowSmallerThan); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - mFilesModel->setCheckState(index, Qt::Unchecked); - } -} - -void DataFilesList::refresh() -{ - mFilesModel->sort(0); - - - // Refresh the plugins table - mFilesTable->scrollToTop(); -} - - -void DataFilesList::setCheckState(QModelIndex index) -{ - if (!index.isValid()) - return; - - QObject *object = QObject::sender(); - - // Not a signal-slot call - if (!object) - return; - - if (object->objectName() == QLatin1String("PluginsTable")) { - QModelIndex sourceIndex = mFilesProxyModel->mapToSource(index); - - (mFilesModel->checkState(sourceIndex) == Qt::Checked) - ? mFilesModel->setCheckState(sourceIndex, Qt::Unchecked) - : mFilesModel->setCheckState(sourceIndex, Qt::Checked); - } - - return; - -} - -void DataFilesList::uncheckAll() -{ - mFilesModel->uncheckAll(); -} - -void DataFilesList::filterChanged(const QString filter) -{ - QRegExp regExp(filter, Qt::CaseInsensitive, QRegExp::FixedString); - mFilesProxyModel->setFilterRegExp(regExp); -} - -void DataFilesList::showContextMenu(const QPoint &point) -{ - // Make sure there are plugins in the view - if (!mFilesTable->selectionModel()->hasSelection()) { - return; - } - - QPoint globalPos = mFilesTable->mapToGlobal(point); - - QModelIndexList indexes = mFilesTable->selectionModel()->selectedIndexes(); - - // Show the check/uncheck actions depending on the state of the selected items - mUncheckAction->setEnabled(false); - mCheckAction->setEnabled(false); - - foreach (const QModelIndex &index, indexes) { - if (!index.isValid()) - return; - - (mFilesModel->checkState(index) == Qt::Checked) - ? mUncheckAction->setEnabled(true) - : mCheckAction->setEnabled(true); - } - - // Show menu - mContextMenu->exec(globalPos); -} - -void DataFilesList::setCheckState(const QString& element, Qt::CheckState state) -{ - EsmFile *file = mFilesModel->findItem(element); - if (file) - { - mFilesModel->setCheckState(mFilesModel->indexFromItem(file), Qt::Checked); - } -} - -QStringList DataFilesList::checkedFiles() -{ - return mFilesModel->checkedItems(); -} diff --git a/components/fileorderlist/datafileslist.hpp b/components/fileorderlist/datafileslist.hpp deleted file mode 100644 index 69a20393c..000000000 --- a/components/fileorderlist/datafileslist.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef DATAFILESLIST_H -#define DATAFILESLIST_H - -#include -#include -#include - - -class QTableView; -class QSortFilterProxyModel; -class QSettings; -class QAction; -class QToolBar; -class QMenu; -class ProfilesComboBox; -class DataFilesModel; - -class TextInputDialog; - -namespace Files { struct ConfigurationManager; } - -class DataFilesList : public QWidget -{ - Q_OBJECT - -public: - DataFilesList(Files::ConfigurationManager& cfg, QWidget *parent = 0); - - bool setupDataFiles(Files::PathContainer dataDirs, const QString encoding); - void selectedFiles(std::vector& paths); - void uncheckAll(); - QStringList checkedFiles(); - void setCheckState(const QString& element, Qt::CheckState); - - -public slots: - void setCheckState(QModelIndex index); - - void filterChanged(const QString filter); - void showContextMenu(const QPoint &point); - - // Action slots -// void moveUp(); -// void moveDown(); -// void moveTop(); -// void moveBottom(); - void check(); - void uncheck(); - void refresh(); - -private: - DataFilesModel *mFilesModel; - - QSortFilterProxyModel *mFilesProxyModel; - - QTableView *mFilesTable; - - QMenu *mContextMenu; - -// QAction *mMoveUpAction; -// QAction *mMoveDownAction; -// QAction *mMoveTopAction; -// QAction *mMoveBottomAction; - QAction *mCheckAction; - QAction *mUncheckAction; - - Files::ConfigurationManager &mCfgMgr; - -// const QStringList checkedPlugins(); -// const QStringList selectedMasters(); - - void createActions(); -}; - -#endif diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 4e9b69dc2..b33e2e12a 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -212,6 +212,7 @@ bool DataFilesModel::setData(const QModelIndex &index, const QVariant &value, in QModelIndex lastIndex = indexFromItem(mFiles.last()); emit dataChanged(firstIndex, lastIndex); + emit checkedItemsChanged(checkedItems()); return true; } diff --git a/components/fileorderlist/model/datafilesmodel.hpp b/components/fileorderlist/model/datafilesmodel.hpp index 0e5008abe..0a07a536f 100644 --- a/components/fileorderlist/model/datafilesmodel.hpp +++ b/components/fileorderlist/model/datafilesmodel.hpp @@ -48,6 +48,9 @@ public: QModelIndex indexFromItem(EsmFile *item) const; EsmFile* findItem(const QString &name); EsmFile* item(int row) const; + +signals: + void checkedItemsChanged(const QStringList &items); private: bool canBeChecked(EsmFile *file) const; diff --git a/apps/launcher/model/pluginsproxymodel.cpp b/components/fileorderlist/model/pluginsproxymodel.cpp similarity index 100% rename from apps/launcher/model/pluginsproxymodel.cpp rename to components/fileorderlist/model/pluginsproxymodel.cpp diff --git a/apps/launcher/model/pluginsproxymodel.hpp b/components/fileorderlist/model/pluginsproxymodel.hpp similarity index 100% rename from apps/launcher/model/pluginsproxymodel.hpp rename to components/fileorderlist/model/pluginsproxymodel.hpp diff --git a/apps/launcher/resources/icons/tango/document-new.png b/files/launcher/icons/tango/document-new.png similarity index 100% rename from apps/launcher/resources/icons/tango/document-new.png rename to files/launcher/icons/tango/document-new.png diff --git a/apps/launcher/resources/icons/tango/edit-copy.png b/files/launcher/icons/tango/edit-copy.png similarity index 100% rename from apps/launcher/resources/icons/tango/edit-copy.png rename to files/launcher/icons/tango/edit-copy.png diff --git a/apps/launcher/resources/icons/tango/edit-delete.png b/files/launcher/icons/tango/edit-delete.png similarity index 100% rename from apps/launcher/resources/icons/tango/edit-delete.png rename to files/launcher/icons/tango/edit-delete.png diff --git a/apps/launcher/resources/icons/tango/go-bottom.png b/files/launcher/icons/tango/go-bottom.png similarity index 100% rename from apps/launcher/resources/icons/tango/go-bottom.png rename to files/launcher/icons/tango/go-bottom.png diff --git a/apps/launcher/resources/icons/tango/go-down.png b/files/launcher/icons/tango/go-down.png similarity index 100% rename from apps/launcher/resources/icons/tango/go-down.png rename to files/launcher/icons/tango/go-down.png diff --git a/apps/launcher/resources/icons/tango/go-top.png b/files/launcher/icons/tango/go-top.png similarity index 100% rename from apps/launcher/resources/icons/tango/go-top.png rename to files/launcher/icons/tango/go-top.png diff --git a/apps/launcher/resources/icons/tango/go-up.png b/files/launcher/icons/tango/go-up.png similarity index 100% rename from apps/launcher/resources/icons/tango/go-up.png rename to files/launcher/icons/tango/go-up.png diff --git a/apps/launcher/resources/icons/tango/index.theme b/files/launcher/icons/tango/index.theme similarity index 100% rename from apps/launcher/resources/icons/tango/index.theme rename to files/launcher/icons/tango/index.theme diff --git a/apps/launcher/resources/icons/tango/video-display.png b/files/launcher/icons/tango/video-display.png similarity index 100% rename from apps/launcher/resources/icons/tango/video-display.png rename to files/launcher/icons/tango/video-display.png diff --git a/apps/launcher/resources/images/clear.png b/files/launcher/images/clear.png similarity index 100% rename from apps/launcher/resources/images/clear.png rename to files/launcher/images/clear.png diff --git a/apps/launcher/resources/images/down.png b/files/launcher/images/down.png similarity index 100% rename from apps/launcher/resources/images/down.png rename to files/launcher/images/down.png diff --git a/apps/launcher/resources/images/openmw-header.png b/files/launcher/images/openmw-header.png similarity index 100% rename from apps/launcher/resources/images/openmw-header.png rename to files/launcher/images/openmw-header.png diff --git a/apps/launcher/resources/images/openmw-plugin.png b/files/launcher/images/openmw-plugin.png similarity index 100% rename from apps/launcher/resources/images/openmw-plugin.png rename to files/launcher/images/openmw-plugin.png diff --git a/apps/launcher/resources/images/openmw.ico b/files/launcher/images/openmw.ico similarity index 100% rename from apps/launcher/resources/images/openmw.ico rename to files/launcher/images/openmw.ico diff --git a/apps/launcher/resources/images/openmw.png b/files/launcher/images/openmw.png similarity index 100% rename from apps/launcher/resources/images/openmw.png rename to files/launcher/images/openmw.png diff --git a/apps/launcher/resources/images/playpage-background.png b/files/launcher/images/playpage-background.png similarity index 100% rename from apps/launcher/resources/images/playpage-background.png rename to files/launcher/images/playpage-background.png diff --git a/files/launcher/launcher.qrc b/files/launcher/launcher.qrc new file mode 100644 index 000000000..19b1c5a6f --- /dev/null +++ b/files/launcher/launcher.qrc @@ -0,0 +1,21 @@ + + + images/clear.png + images/down.png + images/openmw.png + images/openmw-plugin.png + images/openmw-header.png + images/playpage-background.png + + + icons/tango/index.theme + icons/tango/video-display.png + icons/tango/document-new.png + icons/tango/edit-copy.png + icons/tango/edit-delete.png + icons/tango/go-bottom.png + icons/tango/go-down.png + icons/tango/go-top.png + icons/tango/go-up.png + + diff --git a/apps/launcher/ui/datafilespage.ui b/files/ui/datafilespage.ui similarity index 98% rename from apps/launcher/ui/datafilespage.ui rename to files/ui/datafilespage.ui index 91b5475e6..044817fb4 100644 --- a/apps/launcher/ui/datafilespage.ui +++ b/files/ui/datafilespage.ui @@ -59,7 +59,7 @@ - + Current Profile: diff --git a/apps/launcher/ui/graphicspage.ui b/files/ui/graphicspage.ui similarity index 100% rename from apps/launcher/ui/graphicspage.ui rename to files/ui/graphicspage.ui diff --git a/apps/launcher/ui/mainwindow.ui b/files/ui/mainwindow.ui similarity index 100% rename from apps/launcher/ui/mainwindow.ui rename to files/ui/mainwindow.ui diff --git a/apps/launcher/ui/playpage.ui b/files/ui/playpage.ui similarity index 100% rename from apps/launcher/ui/playpage.ui rename to files/ui/playpage.ui From a994a23f4ec1a1fe956216651caea2ff7bd0a127 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 7 Mar 2013 07:56:29 +0100 Subject: [PATCH 908/916] file loading fixes --- apps/opencs/model/doc/document.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index e709cc5bf..11d877d0b 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -18,9 +18,6 @@ void CSMDoc::Document::load (const std::vector::const_i if (lastAsModified) getData().loadFile (*end2, false); - - addOptionalGmsts(); - addOptionalGlobals(); } void CSMDoc::Document::addOptionalGmsts() @@ -199,6 +196,8 @@ void CSMDoc::Document::createBase() getData().getGlobals().add (record); } + + /// \todo add GMSTs } CSMDoc::Document::Document (const std::vector& files, bool new_) @@ -213,7 +212,9 @@ CSMDoc::Document::Document (const std::vector& files, b mName = files.back().filename().string(); - if (files.size()>1 || !new_) + if (new_ && files.size()==1) + createBase(); + else if (files.size()>1) { std::vector::const_iterator end = files.end(); @@ -223,8 +224,8 @@ CSMDoc::Document::Document (const std::vector& files, b load (files.begin(), end, !new_); } - if (new_ && files.size()==1) - createBase(); + addOptionalGmsts(); + addOptionalGlobals(); connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); From e34685b8a314d49d6353876c3634022a5ad444af Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Mar 2013 12:46:26 +0100 Subject: [PATCH 909/916] Fix manually changed mouse cursor --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/cursor.cpp | 5 +++-- apps/openmw/mwgui/hud.cpp | 11 +++++------ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 81d7cb9fe..93cc8e44a 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -237,6 +237,8 @@ namespace MWBase virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; + virtual void changePointer (const std::string& name) = 0; + virtual const Translation::Storage& getTranslationDataStorage() const = 0; }; } diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index 399695ae3..b0d164bed 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -13,8 +13,9 @@ namespace MWGui { - ResourceImageSetPointerFix::ResourceImageSetPointerFix() : - mImageSet(NULL) + ResourceImageSetPointerFix::ResourceImageSetPointerFix() + : mImageSet(NULL) + , mRotation(0) { } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index cebc457db..0a31a428b 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -4,7 +4,6 @@ #include #include -#include #include @@ -222,7 +221,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) else world->dropObjectOnGround(world->getPlayer().getPlayer(), object); - MyGUI::PointerManager::getInstance().setPointer("arrow"); + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); std::string sound = MWWorld::Class::get(object).getDownSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); @@ -273,21 +272,21 @@ void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) bool canDrop = world->canPlaceObject(mouseX, mouseY); if (!canDrop) - MyGUI::PointerManager::getInstance().setPointer("drop_ground"); + MWBase::Environment::get().getWindowManager()->changePointer("drop_ground"); else - MyGUI::PointerManager::getInstance().setPointer("arrow"); + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); } else { - MyGUI::PointerManager::getInstance().setPointer("arrow"); + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); mWorldMouseOver = true; } } void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) { - MyGUI::PointerManager::getInstance().setPointer("arrow"); + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); mWorldMouseOver = false; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eb8d4c191..d866ec755 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1127,3 +1127,8 @@ const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; } + +void WindowManager::changePointer(const std::string &name) +{ + mCursor->onCursorChange(name); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7786af31a..122b10cc3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -228,6 +228,8 @@ namespace MWGui virtual void startEnchanting(MWWorld::Ptr actor); virtual void startTraining(MWWorld::Ptr actor); + virtual void changePointer (const std::string& name); + virtual const Translation::Storage& getTranslationDataStorage() const; private: From 0ee0dbdb971bb5ae09ef256173f69d46ba1cd303 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Mar 2013 14:00:13 +0100 Subject: [PATCH 910/916] Added "dispose corpse" button, added stealing (all items visible and no penalty yet) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwgui/container.cpp | 66 +++++++++++++++++++--- apps/openmw/mwgui/container.hpp | 10 +++- apps/openmw/mwgui/inventorywindow.cpp | 18 ------ apps/openmw/mwgui/inventorywindow.hpp | 1 - apps/openmw/mwgui/tradewindow.cpp | 27 +-------- apps/openmw/mwgui/tradewindow.hpp | 4 -- apps/openmw/mwworld/actionopen.cpp | 6 +- apps/openmw/mwworld/actionopen.hpp | 8 ++- files/mygui/openmw_container_window.layout | 4 ++ 11 files changed, 87 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 90dc70715..19f327dcb 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -132,7 +132,7 @@ namespace MWClass const MWWorld::Ptr& actor) const { if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - return boost::shared_ptr (new MWWorld::ActionOpen(ptr)); + return boost::shared_ptr (new MWWorld::ActionOpen(ptr, true)); else return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b1263c2e5..f074d0368 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -220,7 +220,9 @@ namespace MWClass const MWWorld::Ptr& actor) const { if (MWWorld::Class::get (ptr).getCreatureStats (ptr).isDead()) - return boost::shared_ptr (new MWWorld::ActionOpen(ptr)); + return boost::shared_ptr (new MWWorld::ActionOpen(ptr, true)); + else if (MWWorld::Class::get(actor).getStance(actor, MWWorld::Class::Sneak)) + return boost::shared_ptr (new MWWorld::ActionOpen(ptr)); // stealing else return boost::shared_ptr (new MWWorld::ActionTalk (ptr)); } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 479a82efa..2b8000312 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -15,6 +15,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -70,9 +71,11 @@ namespace } -ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) : - mDragAndDrop(dragAndDrop), - mFilter(ContainerBase::Filter_All) +ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) + : mDragAndDrop(dragAndDrop) + , mFilter(ContainerBase::Filter_All) + , mDisplayEquippedItems(true) + , mHighlightEquippedItems(true) { } @@ -313,7 +316,6 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); } - std::cout << "container weight " << curWeight << "/" << capacity << std::endl; } else { @@ -430,7 +432,7 @@ void ContainerBase::drawItems() equippedItems.erase(found); } // and add the items that are left (= have the correct category) - if (!ignoreEquippedItems()) + if (mDisplayEquippedItems && mHighlightEquippedItems) { for (std::vector::const_iterator it=equippedItems.begin(); it != equippedItems.end(); ++it) @@ -445,7 +447,8 @@ void ContainerBase::drawItems() std::vector regularItems; for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) { - if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() + if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() + || (!mHighlightEquippedItems && mDisplayEquippedItems)) && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) regularItems.push_back(*iter); @@ -587,6 +590,27 @@ void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) } } +std::vector ContainerBase::getEquippedItems() +{ + if (mPtr.getTypeName() != typeid(ESM::NPC).name()) + return std::vector(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + + std::vector items; + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) + { + items.push_back(*it); + } + } + + return items; +} + MWWorld::ContainerStore& ContainerBase::getContainerStore() { MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); @@ -599,6 +623,7 @@ ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAnd : ContainerBase(dragAndDrop) , WindowBase("openmw_container_window.layout", parWindowManager) { + getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mTakeButton, "TakeButton"); getWidget(mCloseButton, "CloseButton"); @@ -608,6 +633,7 @@ ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAnd getWidget(itemView, "ItemView"); setWidgets(containerWidget, itemView); + mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); @@ -625,8 +651,18 @@ void ContainerWindow::onWindowResize(MyGUI::Window* window) drawItems(); } -void ContainerWindow::open(MWWorld::Ptr container) +void ContainerWindow::open(MWWorld::Ptr container, bool loot) { + mDisplayEquippedItems = true; + mHighlightEquippedItems = false; + if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) + { + // we are stealing stuff + mDisplayEquippedItems = false; + } + + mDisposeCorpseButton->setVisible(loot); + openContainer(container); setTitle(MWWorld::Class::get(container).getName(container)); drawItems(); @@ -671,6 +707,22 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) } } +void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) +{ + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + onTakeAllButtonClicked(mTakeButton); + + /// \todo I don't think this is the correct flag to check + if (MWWorld::Class::get(mPtr).isEssential(mPtr)) + mWindowManager.messageBox("#{sDisposeCorpseFail}"); + else + MWBase::Environment::get().getWorld()->deleteObject(mPtr); + + mPtr = MWWorld::Ptr(); + } +} + void ContainerWindow::onReferenceUnavailable() { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 08d425032..3c8127b26 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -82,6 +82,9 @@ namespace MWGui void drawItems(); protected: + bool mDisplayEquippedItems; + bool mHighlightEquippedItems; + MyGUI::ScrollView* mItemView; MyGUI::Widget* mContainerWidget; @@ -111,14 +114,13 @@ namespace MWGui virtual bool isTradeWindow() { return false; } virtual bool isInventory() { return false; } - virtual std::vector getEquippedItems() { return std::vector(); } + virtual std::vector getEquippedItems(); virtual void _unequipItem(MWWorld::Ptr item) { ; } virtual bool isTrading() { return false; } virtual void onSelectedItemImpl(MWWorld::Ptr item) { ; } - virtual bool ignoreEquippedItems() { return false; } virtual std::vector itemsToIgnore() { return std::vector(); } virtual void notifyContentChanged() { ; } @@ -131,15 +133,17 @@ namespace MWGui virtual ~ContainerWindow(); - void open(MWWorld::Ptr container); + void open(MWWorld::Ptr container, bool loot=false); protected: + MyGUI::Button* mDisposeCorpseButton; MyGUI::Button* mTakeButton; MyGUI::Button* mCloseButton; void onWindowResize(MyGUI::Window* window); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); + void onDisposeCorpseButtonClicked(MyGUI::Widget* sender); virtual void onReferenceUnavailable(); }; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4a0234644..ab7615c0e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -211,24 +211,6 @@ namespace MWGui return MWWorld::Ptr(); } - std::vector InventoryWindow::getEquippedItems() - { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - - std::vector items; - - for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) - { - MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); - if (it != invStore.end()) - { - items.push_back(*it); - } - } - - return items; - } - void InventoryWindow::_unequipItem(MWWorld::Ptr item) { MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 6b45a9980..7c59bab50 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -64,7 +64,6 @@ namespace MWGui virtual bool isTrading() { return mTrading; } virtual bool isInventory() { return true; } - virtual std::vector getEquippedItems(); virtual void _unequipItem(MWWorld::Ptr item); virtual void onReferenceUnavailable() { ; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index e3cf8ea3a..1b82d741c 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -31,6 +31,9 @@ namespace MWGui , mBalanceButtonsState(BBS_None) , mBalanceChangePause(0.0) { + // items the NPC is wearing should not be for trade + mDisplayEquippedItems = true; + MyGUI::ScrollView* itemView; MyGUI::Widget* containerWidget; getWidget(containerWidget, "Items"); @@ -337,30 +340,6 @@ namespace MWGui mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(getMerchantGold())); } - std::vector TradeWindow::getEquippedItems() - { - std::vector items; - - if (mPtr.getTypeName() == typeid(ESM::Creature).name()) - { - // creatures don't have equipment slots. - return items; - } - - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - - for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) - { - MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); - if (it != invStore.end()) - { - items.push_back(*it); - } - } - - return items; - } - bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item) { int services = 0; diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index ea749f5a2..2e05d03d5 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -82,10 +82,6 @@ namespace MWGui void onIncreaseButtonTriggered(); void onDecreaseButtonTriggered(); - // don't show items that the NPC has equipped in his trade-window. - virtual bool ignoreEquippedItems() { return true; } - virtual std::vector getEquippedItems(); - virtual bool isTrading() { return true; } virtual bool isTradeWindow() { return true; } diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 040a3856e..728b6e32b 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -10,7 +10,9 @@ namespace MWWorld { - ActionOpen::ActionOpen (const MWWorld::Ptr& container) : Action (false, container) + ActionOpen::ActionOpen (const MWWorld::Ptr& container, bool loot) + : Action (false, container) + , mLoot(loot) { } @@ -20,6 +22,6 @@ namespace MWWorld return; MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget()); + MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget(), mLoot); } } diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index c49ebefa5..8578995ae 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -13,8 +13,12 @@ namespace MWWorld virtual void executeImp (const MWWorld::Ptr& actor); public: - ActionOpen (const Ptr& container); - ///< \param The Container the Player has activated. + ActionOpen (const Ptr& container, bool loot=false); + ///< \param container The Container the Player has activated. + /// \param loot If true, display the "dispose of corpse" button + + private: + bool mLoot; }; } diff --git a/files/mygui/openmw_container_window.layout b/files/mygui/openmw_container_window.layout index 94e9458a5..452196aae 100644 --- a/files/mygui/openmw_container_window.layout +++ b/files/mygui/openmw_container_window.layout @@ -15,6 +15,10 @@ + + + + From 66a754e9aa515b5b5c9e993e8608ef501b59110c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Mar 2013 15:25:22 +0100 Subject: [PATCH 911/916] Fix tooltip position when hovering the crosshair over NPCs --- apps/openmw/mwworld/worldimp.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7d3efe3e8..33a9b52bf 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -996,13 +996,7 @@ namespace MWWorld if (!object.isEmpty ()) { Ogre::SceneNode* node = object.getRefData().getBaseNode(); - Ogre::AxisAlignedBox bounds; - int i; - for (i=0; inumAttachedObjects(); ++i) - { - Ogre::MovableObject* ob = node->getAttachedObject(i); - bounds.merge(ob->getWorldBoundingBox()); - } + Ogre::AxisAlignedBox bounds = node->_getWorldAABB(); if (bounds.isFinite()) { Vector4 screenCoords = mRendering->boundingBoxToScreen(bounds); From f2f4b6e2d5f5e91f752f7f42860118a739a3e865 Mon Sep 17 00:00:00 2001 From: Michal Sciubidlo Date: Thu, 7 Mar 2013 20:15:01 +0100 Subject: [PATCH 912/916] Make MWWorld::getInterior case insensitive. Interior cells names can use different mix of uppercase/lowercase in different places. getInterior() should return same cell in all cases. Fixes bug #586. --- apps/openmw/mwworld/cells.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index b912f5ccc..f95d30df1 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -129,13 +129,14 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) MWWorld::Ptr::CellStore *MWWorld::Cells::getInterior (const std::string& name) { - std::map::iterator result = mInteriors.find (name); + std::string lowerName = Misc::StringUtils::lowerCase(name); + std::map::iterator result = mInteriors.find (lowerName); if (result==mInteriors.end()) { - const ESM::Cell *cell = mStore.get().find(name); + const ESM::Cell *cell = mStore.get().find(lowerName); - result = mInteriors.insert (std::make_pair (name, Ptr::CellStore (cell))).first; + result = mInteriors.insert (std::make_pair (lowerName, Ptr::CellStore (cell))).first; } if (result->second.mState!=Ptr::CellStore::State_Loaded) From 3adf3f51212c4330010bf04c63687b7593c29b6f Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Tue, 5 Mar 2013 00:45:25 +0100 Subject: [PATCH 913/916] Revive bsatool --- CMakeLists.txt | 13 ++- apps/bsatool/CMakeLists.txt | 26 ++++++ apps/bsatool/bsatool.cpp | 86 +++++++++++++++++ .../bsa/tests => apps/bsatool}/bsatool.ggo | 0 .../bsa/tests => apps/bsatool}/bsatool_cmd.c | 62 ++++++------- .../bsa/tests => apps/bsatool}/bsatool_cmd.h | 6 +- components/bsa/tests/Makefile | 9 +- components/bsa/tests/bsatool.cpp | 92 ------------------- 8 files changed, 159 insertions(+), 135 deletions(-) create mode 100644 apps/bsatool/CMakeLists.txt create mode 100644 apps/bsatool/bsatool.cpp rename {components/bsa/tests => apps/bsatool}/bsatool.ggo (100%) rename {components/bsa/tests => apps/bsatool}/bsatool_cmd.c (99%) rename {components/bsa/tests => apps/bsatool}/bsatool_cmd.h (98%) delete mode 100644 components/bsa/tests/bsatool.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6498e723c..395027479 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binarie option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) # Apps and tools +option(BUILD_BSATOOL "build BSA extractor" OFF) option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) @@ -352,7 +353,7 @@ if(DPKG_PROGRAM) Data files from the original game is required to run it.") SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") - SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") + SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") @@ -446,6 +447,10 @@ add_subdirectory (components) # Apps and tools add_subdirectory( apps/openmw ) +if (BUILD_BSATOOL) + add_subdirectory( apps/bsatool ) +endif() + if (BUILD_ESMTOOL) add_subdirectory( apps/esmtool ) endif() @@ -532,6 +537,9 @@ if (WIN32) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif (BUILD_LAUNCHER) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) + if (BUILD_BSATOOL) + set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS}) + endif (BUILD_BSATOOL) if (BUILD_ESMTOOL) set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif (BUILD_ESMTOOL) @@ -656,6 +664,9 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) IF(BUILD_LAUNCHER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) ENDIF(BUILD_LAUNCHER) + IF(BUILD_BSATOOL) + INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) + ENDIF(BUILD_BSATOOL) IF(BUILD_ESMTOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) ENDIF(BUILD_ESMTOOL) diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt new file mode 100644 index 000000000..8e33f0675 --- /dev/null +++ b/apps/bsatool/CMakeLists.txt @@ -0,0 +1,26 @@ +set(BSATOOL + bsatool.cpp + bsatool_cmd.c + bsatool_cmd.h +) +source_group(apps\\bsatool FILES ${BSATOOL}) + +# Main executable +add_executable(bsatool + ${BSATOOL} +) + +target_link_libraries(bsatool + ${Boost_LIBRARIES} + components +) + +#if (APPLE) +# find_library(CARBON_FRAMEWORK Carbon) +# target_link_libraries(openmw ${CARBON_FRAMEWORK}) +#endif (APPLE) + +if (BUILD_WITH_CODE_COVERAGE) + add_definitions (--coverage) + target_link_libraries(bsatool gcov) +endif() diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp new file mode 100644 index 000000000..2d15f8cf7 --- /dev/null +++ b/apps/bsatool/bsatool.cpp @@ -0,0 +1,86 @@ +#include + +#include "bsatool_cmd.h" + +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + gengetopt_args_info info; + + if(cmdline_parser(argc, argv, &info) != 0) + return 1; + + if(info.inputs_num != 1) + { + if(info.inputs_num == 0) + std::cout << "ERROR: missing BSA file\n\n"; + else + std::cout << "ERROR: more than one BSA file specified\n\n"; + cmdline_parser_print_help(); + return 1; + } + + // Open file + Bsa::BSAFile bsa; + char *arcname = info.inputs[0]; + try { bsa.open(arcname); } + catch(std::exception &e) + { + std::cout << "ERROR reading BSA archive '" << arcname + << "'\nDetails:\n" << e.what() << std::endl; + return 2; + } + + if(info.extract_given) + { + char *file = info.extract_arg; + + if(!bsa.exists(file)) + { + std::cout << "ERROR: file '" << file << "' not found\n"; + std::cout << "In archive: " << arcname << std::endl; + return 3; + } + + // Find the base name of the file + int pos = strlen(file); + while(pos > 0 && file[pos] != '\\') pos--; + char *base = file+pos+1; + + // TODO: We might add full directory name extraction later. We + // could also allow automatic conversion from / to \ in + // parameter file names. + + // Load the file into a memory buffer + Ogre::DataStreamPtr data = bsa.getFile(file); + + // Write the file to disk + std::ofstream out(base, std::ios::binary); + out.write(data->getAsString().c_str(), data->size()); + out.close(); + + return 0; + } + + // List all files + const Bsa::BSAFile::FileList &files = bsa.getList(); + for(int i=0; i -#include +#include +#include #include #ifndef FIX_UNUSED @@ -71,7 +71,7 @@ void clear_args (struct gengetopt_args_info *args_info) FIX_UNUSED (args_info); args_info->extract_arg = NULL; args_info->extract_orig = NULL; - + } static @@ -83,7 +83,7 @@ void init_args_info(struct gengetopt_args_info *args_info) args_info->version_help = gengetopt_args_info_help[1] ; args_info->extract_help = gengetopt_args_info_help[2] ; args_info->long_help = gengetopt_args_info_help[3] ; - + } void @@ -133,7 +133,7 @@ void cmdline_parser_params_init(struct cmdline_parser_params *params) { if (params) - { + { params->override = 0; params->initialize = 1; params->check_required = 1; @@ -145,9 +145,9 @@ cmdline_parser_params_init(struct cmdline_parser_params *params) struct cmdline_parser_params * cmdline_parser_params_create(void) { - struct cmdline_parser_params *params = + struct cmdline_parser_params *params = (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); - cmdline_parser_params_init(params); + cmdline_parser_params_init(params); return params; } @@ -168,8 +168,8 @@ cmdline_parser_release (struct gengetopt_args_info *args_info) unsigned int i; free_string_field (&(args_info->extract_arg)); free_string_field (&(args_info->extract_orig)); - - + + for (i = 0; i < args_info->inputs_num; ++i) free (args_info->inputs [i]); @@ -211,7 +211,7 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) write_into_file(outfile, "extract", args_info->extract_orig, 0); if (args_info->long_given) write_into_file(outfile, "long", 0, 0 ); - + i = EXIT_SUCCESS; return i; @@ -276,7 +276,7 @@ cmdline_parser_ext (int argc, char * const *argv, struct gengetopt_args_info *ar cmdline_parser_free (args_info); exit (EXIT_FAILURE); } - + return result; } @@ -285,7 +285,7 @@ cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_ { int result; struct cmdline_parser_params params; - + params.override = override; params.initialize = initialize; params.check_required = check_required; @@ -299,7 +299,7 @@ cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_ cmdline_parser_free (args_info); exit (EXIT_FAILURE); } - + return result; } @@ -324,7 +324,7 @@ cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog * */ -/* +/* * we must include anything we need since this file is not thought to be * inserted in a file already using getopt.h * @@ -859,7 +859,7 @@ static int getopt_internal_r(int argc, char *const *argv, const char *optstring, return -1; d->custom_optarg = NULL; - /* + /* * This is a big difference with GNU getopt, since optind == 0 * means initialization while here 1 means first call. */ @@ -926,7 +926,7 @@ static char *package_name = 0; */ static int update_arg(void *field, char **orig_field, - unsigned int *field_given, unsigned int *prev_given, + unsigned int *field_given, unsigned int *prev_given, char *value, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, @@ -947,18 +947,18 @@ int update_arg(void *field, char **orig_field, if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) { if (short_opt != '-') - fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", + fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", package_name, long_opt, short_opt, (additional_error ? additional_error : "")); else - fprintf (stderr, "%s: `--%s' option given more than once%s\n", + fprintf (stderr, "%s: `--%s' option given more than once%s\n", package_name, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } FIX_UNUSED (default_value); - + if (field_given && *field_given && ! override) return 0; if (prev_given) @@ -1011,7 +1011,7 @@ cmdline_parser_internal ( int error = 0; struct gengetopt_args_info local_args_info; - + int override; int initialize; int check_required; @@ -1021,9 +1021,9 @@ cmdline_parser_internal ( int optind; int opterr; int optopt; - + package_name = argv[0]; - + override = params->override; initialize = params->initialize; check_required = params->check_required; @@ -1078,28 +1078,28 @@ cmdline_parser_internal ( exit (EXIT_SUCCESS); case 'x': /* Extract file from archive. */ - - - if (update_arg( (void *)&(args_info->extract_arg), + + + if (update_arg( (void *)&(args_info->extract_arg), &(args_info->extract_orig), &(args_info->extract_given), &(local_args_info.extract_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "extract", 'x', additional_error)) goto failure; - + break; case 'l': /* Include extra information in archive listing. */ - - - if (update_arg( 0 , + + + if (update_arg( 0 , 0 , &(args_info->long_given), &(local_args_info.long_given), optarg, 0, 0, ARG_NO, check_ambiguity, override, 0, 0, "long", 'l', additional_error)) goto failure; - + break; case 0: /* Long option with no short option */ @@ -1140,7 +1140,7 @@ cmdline_parser_internal ( return 0; failure: - + cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } diff --git a/components/bsa/tests/bsatool_cmd.h b/apps/bsatool/bsatool_cmd.h similarity index 98% rename from components/bsa/tests/bsatool_cmd.h rename to apps/bsatool/bsatool_cmd.h index 98fe2633f..4d5f80ea2 100644 --- a/components/bsa/tests/bsatool_cmd.h +++ b/apps/bsatool/bsatool_cmd.h @@ -13,7 +13,7 @@ #include "config.h" #endif -#include /* for FILE */ +#include /* for FILE */ #ifdef __cplusplus extern "C" { @@ -43,7 +43,7 @@ struct gengetopt_args_info char * extract_orig; /**< @brief Extract file from archive original value given at command line. */ const char *extract_help; /**< @brief Extract file from archive help description. */ const char *long_help; /**< @brief Include extra information in archive listing help description. */ - + unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int extract_given ; /**< @brief Whether extract was given. */ @@ -136,7 +136,7 @@ void cmdline_parser_print_help(void); void cmdline_parser_print_version(void); /** - * Initializes all the fields a cmdline_parser_params structure + * Initializes all the fields a cmdline_parser_params structure * to their default values * @param params the structure to initialize */ diff --git a/components/bsa/tests/Makefile b/components/bsa/tests/Makefile index bc2bf4e50..73e20d7b3 100644 --- a/components/bsa/tests/Makefile +++ b/components/bsa/tests/Makefile @@ -1,6 +1,6 @@ GCC=g++ -all: bsa_file_test bsatool ogre_archive_test +all: bsa_file_test ogre_archive_test I_OGRE=$(shell pkg-config --cflags OGRE) L_OGRE=$(shell pkg-config --libs OGRE) @@ -11,12 +11,5 @@ bsa_file_test: bsa_file_test.cpp ../bsa_file.cpp ogre_archive_test: ogre_archive_test.cpp ../bsa_file.cpp ../bsa_archive.cpp $(GCC) $^ -o $@ $(I_OGRE) $(L_OGRE) -bsatool: bsatool.cpp ../bsa_file.cpp bsatool_cmd.c - $(GCC) $^ -o $@ - -bsatool_cmd.c: bsatool.ggo - gengetopt < bsatool.ggo - clean: rm *_test - rm bsatool diff --git a/components/bsa/tests/bsatool.cpp b/components/bsa/tests/bsatool.cpp deleted file mode 100644 index df37e3827..000000000 --- a/components/bsa/tests/bsatool.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "../bsa_file.hpp" - -#include "bsatool_cmd.h" - -#include -#include -#include -#include - -#include "../../mangle/stream/filters/buffer_stream.hpp" - -using namespace std; -using namespace Mangle::Stream; -using namespace Bsa; - -int main(int argc, char** argv) -{ - gengetopt_args_info info; - - if(cmdline_parser(argc, argv, &info) != 0) - return 1; - - if(info.inputs_num != 1) - { - if(info.inputs_num == 0) - cout << "ERROR: missing BSA file\n\n"; - else - cout << "ERROR: more than one BSA file specified\n\n"; - cmdline_parser_print_help(); - return 1; - } - - // Open file - BSAFile bsa; - char *arcname = info.inputs[0]; - try { bsa.open(arcname); } - catch(exception &e) - { - cout << "ERROR reading BSA archive '" << arcname - << "'\nDetails:\n" << e.what() << endl; - return 2; - } - - if(info.extract_given) - { - char *file = info.extract_arg; - - if(!bsa.exists(file)) - { - cout << "ERROR: file '" << file << "' not found\n"; - cout << "In archive: " << arcname << endl; - return 3; - } - - // Find the base name of the file - int pos = strlen(file); - while(pos > 0 && file[pos] != '\\') pos--; - char *base = file+pos+1; - - // TODO: We might add full directory name extraction later. We - // could also allow automatic conversion from / to \ in - // parameter file names. - - // Load the file into a memory buffer - BufferStream data(bsa.getFile(file)); - - // Write the file to disk - ofstream out(base, ios::binary); - out.write((char*)data.getPtr(), data.size()); - out.close(); - - return 0; - } - - // List all files - const BSAFile::FileList &files = bsa.getList(); - for(int i=0; i Date: Thu, 7 Mar 2013 21:05:56 +0100 Subject: [PATCH 914/916] Bsatool: extract and extractall modes --- apps/bsatool/CMakeLists.txt | 7 - apps/bsatool/bsatool.cpp | 304 ++++++++-- apps/bsatool/bsatool.ggo | 11 - apps/bsatool/bsatool_cmd.c | 1146 ----------------------------------- apps/bsatool/bsatool_cmd.h | 179 ------ 5 files changed, 253 insertions(+), 1394 deletions(-) delete mode 100644 apps/bsatool/bsatool.ggo delete mode 100644 apps/bsatool/bsatool_cmd.c delete mode 100644 apps/bsatool/bsatool_cmd.h diff --git a/apps/bsatool/CMakeLists.txt b/apps/bsatool/CMakeLists.txt index 8e33f0675..3f1988a70 100644 --- a/apps/bsatool/CMakeLists.txt +++ b/apps/bsatool/CMakeLists.txt @@ -1,7 +1,5 @@ set(BSATOOL bsatool.cpp - bsatool_cmd.c - bsatool_cmd.h ) source_group(apps\\bsatool FILES ${BSATOOL}) @@ -15,11 +13,6 @@ target_link_libraries(bsatool components ) -#if (APPLE) -# find_library(CARBON_FRAMEWORK Carbon) -# target_link_libraries(openmw ${CARBON_FRAMEWORK}) -#endif (APPLE) - if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(bsatool gcov) diff --git a/apps/bsatool/bsatool.cpp b/apps/bsatool/bsatool.cpp index 2d15f8cf7..e6fcc2567 100644 --- a/apps/bsatool/bsatool.cpp +++ b/apps/bsatool/bsatool.cpp @@ -1,76 +1,192 @@ +#include +#include +#include + +#include +#include +#include + #include -#include "bsatool_cmd.h" +#define BSATOOL_VERSION 1.1 -#include -#include -#include -#include +// Create local aliases for brevity +namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; + +struct Arguments +{ + std::string mode; + std::string filename; + std::string extractfile; + std::string outdir; + + bool longformat; + bool fullpath; +}; + +void replaceAll(std::string& str, const std::string& needle, const std::string& substitute) +{ + int pos = str.find(needle); + while(pos != -1) + { + str.replace(pos, needle.size(), substitute); + pos = str.find(needle); + } +} + +bool parseOptions (int argc, char** argv, Arguments &info) +{ + bpo::options_description desc("Inspect and extract files from Bethesda BSA archives\n\n" + "Usages:\n" + " bsatool list [-l] archivefile\n" + " List the files presents in the input archive.\n\n" + " bsatool extract [-f] archivefile [file_to_extract] [output_directory]\n" + " Extract a file from the input archive.\n\n" + " bsatool extractall archivefile [output_directory]\n" + " Extract all files from the input archive.\n\n" + "Allowed options"); + + desc.add_options() + ("help,h", "print help message.") + ("version,v", "print version information and quit.") + ("long,l", "Include extra information in archive listing.") + ("full-path,f", "Create diretory hierarchy on file extraction " + "(always true for extractall).") + ; + + // input-file is hidden and used as a positional argument + bpo::options_description hidden("Hidden Options"); + + hidden.add_options() + ( "mode,m", bpo::value(), "bsatool mode") + ( "input-file,i", bpo::value< std::vector >(), "input file") + ; + + bpo::positional_options_description p; + p.add("mode", 1).add("input-file", 3); + + // there might be a better way to do this + bpo::options_description all; + all.add(desc).add(hidden); + + bpo::variables_map variables; + try + { + bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv) + .options(all).positional(p).run(); + bpo::store(valid_opts, variables); + } + catch(std::exception &e) + { + std::cout << "ERROR parsing arguments: " << e.what() << "\n\n" + << desc << std::endl; + return false; + } + + bpo::notify(variables); + + if (variables.count ("help")) + { + std::cout << desc << std::endl; + return false; + } + if (variables.count ("version")) + { + std::cout << "BSATool version " << BSATOOL_VERSION << std::endl; + return false; + } + if (!variables.count("mode")) + { + std::cout << "ERROR: no mode specified!\n\n" + << desc << std::endl; + return false; + } + + info.mode = variables["mode"].as(); + if (!(info.mode == "list" || info.mode == "extract" || info.mode == "extractall")) + { + std::cout << std::endl << "ERROR: invalid mode \"" << info.mode << "\"\n\n" + << desc << std::endl; + return false; + } + + if (!variables.count("input-file")) + { + std::cout << "\nERROR: missing BSA archive\n\n" + << desc << std::endl; + return false; + } + info.filename = variables["input-file"].as< std::vector >()[0]; + + // Default output to the working directory + info.outdir = "."; + + if (info.mode == "extract") + { + if (variables["input-file"].as< std::vector >().size() < 2) + { + std::cout << "\nERROR: file to extract unspecified\n\n" + << desc << std::endl; + return false; + } + if (variables["input-file"].as< std::vector >().size() > 1) + info.extractfile = variables["input-file"].as< std::vector >()[1]; + if (variables["input-file"].as< std::vector >().size() > 2) + info.outdir = variables["input-file"].as< std::vector >()[2]; + } + else if (variables["input-file"].as< std::vector >().size() > 1) + info.outdir = variables["input-file"].as< std::vector >()[1]; + + info.longformat = variables.count("long"); + info.fullpath = variables.count("full-path"); + + return true; +} + +int list(Bsa::BSAFile& bsa, Arguments& info); +int extract(Bsa::BSAFile& bsa, Arguments& info); +int extractAll(Bsa::BSAFile& bsa, Arguments& info); int main(int argc, char** argv) { - gengetopt_args_info info; - - if(cmdline_parser(argc, argv, &info) != 0) + Arguments info; + if(!parseOptions (argc, argv, info)) return 1; - if(info.inputs_num != 1) - { - if(info.inputs_num == 0) - std::cout << "ERROR: missing BSA file\n\n"; - else - std::cout << "ERROR: more than one BSA file specified\n\n"; - cmdline_parser_print_help(); - return 1; - } - // Open file Bsa::BSAFile bsa; - char *arcname = info.inputs[0]; - try { bsa.open(arcname); } + try + { + bsa.open(info.filename); + } catch(std::exception &e) { - std::cout << "ERROR reading BSA archive '" << arcname + std::cout << "ERROR reading BSA archive '" << info.filename << "'\nDetails:\n" << e.what() << std::endl; return 2; } - if(info.extract_given) + if (info.mode == "list") + return list(bsa, info); + else if (info.mode == "extract") + return extract(bsa, info); + else if (info.mode == "extractall") + return extractAll(bsa, info); + else { - char *file = info.extract_arg; - - if(!bsa.exists(file)) - { - std::cout << "ERROR: file '" << file << "' not found\n"; - std::cout << "In archive: " << arcname << std::endl; - return 3; - } - - // Find the base name of the file - int pos = strlen(file); - while(pos > 0 && file[pos] != '\\') pos--; - char *base = file+pos+1; - - // TODO: We might add full directory name extraction later. We - // could also allow automatic conversion from / to \ in - // parameter file names. - - // Load the file into a memory buffer - Ogre::DataStreamPtr data = bsa.getFile(file); - - // Write the file to disk - std::ofstream out(base, std::ios::binary); - out.write(data->getAsString().c_str(), data->size()); - out.close(); - - return 0; + std::cout << "Unsupported mode. That is not supposed to happen." << std::endl; + return 1; } +} +int list(Bsa::BSAFile& bsa, Arguments& info) +{ // List all files const Bsa::BSAFile::FileList &files = bsa.getList(); for(int i=0; igetAsString().c_str(), data->size()); + out.close(); + + return 0; +} + +int extractAll(Bsa::BSAFile& bsa, Arguments& info) +{ + // Get the list of files present in the archive + Bsa::BSAFile::FileList list = bsa.getList(); + + // Iter on the list + for(Bsa::BSAFile::FileList::iterator it = list.begin(); it != list.end(); ++it) { + const char* archivePath = it->name; + + std::string extractPath (archivePath); + replaceAll(extractPath, "\\", "/"); + + // Get the target path (the path the file will be extracted to) + bfs::path target (info.outdir); + target /= extractPath; + + // Create the directory hierarchy + bfs::create_directories(target.parent_path()); + + bfs::file_status s = bfs::status(target.parent_path()); + if (!bfs::is_directory(s)) + { + std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl; + return 3; + } + + // Get a stream for the file to extract + // (inefficient because getFile iter on the list again) + Ogre::DataStreamPtr 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.close(); + } + return 0; } diff --git a/apps/bsatool/bsatool.ggo b/apps/bsatool/bsatool.ggo deleted file mode 100644 index 2e4227a1b..000000000 --- a/apps/bsatool/bsatool.ggo +++ /dev/null @@ -1,11 +0,0 @@ -package "bsatool" -version "1.0" -purpose "Inspect and extract files from Bethesda BSA archives" -#usage "" -#description "" -args "--unamed-opts=BSA-FILE -F bsatool_cmd -G" - -option "extract" x "Extract file from archive" string optional -option "long" l "Include extra information in archive listing" optional - -text "\nIf no option is given, the default action is to list all files in the archive." diff --git a/apps/bsatool/bsatool_cmd.c b/apps/bsatool/bsatool_cmd.c deleted file mode 100644 index 0b0ed66c2..000000000 --- a/apps/bsatool/bsatool_cmd.c +++ /dev/null @@ -1,1146 +0,0 @@ -/* - File autogenerated by gengetopt version 2.22.2 - generated with the following command: - gengetopt --unamed-opts=BSA-FILE -F bsatool_cmd -G - - The developers of gengetopt consider the fixed text that goes in all - gengetopt output files to be in the public domain: - we make no copyright claims on it. -*/ - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#ifndef FIX_UNUSED -#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ -#endif - - -#include "bsatool_cmd.h" - -const char *gengetopt_args_info_purpose = "Inspect and extract files from Bethesda BSA archives"; - -const char *gengetopt_args_info_usage = "Usage: bsatool [OPTIONS]... [BSA-FILE]..."; - -const char *gengetopt_args_info_description = ""; - -const char *gengetopt_args_info_help[] = { - " -h, --help Print help and exit", - " -V, --version Print version and exit", - " -x, --extract=STRING Extract file from archive", - " -l, --long Include extra information in archive listing", - "\nIf no option is given, the default action is to list all files in the archive.", - 0 -}; - -typedef enum {ARG_NO - , ARG_STRING -} cmdline_parser_arg_type; - -static -void clear_given (struct gengetopt_args_info *args_info); -static -void clear_args (struct gengetopt_args_info *args_info); - -static int -cmdline_parser_internal (int argc, char * const *argv, struct gengetopt_args_info *args_info, - struct cmdline_parser_params *params, const char *additional_error); - - -static char * -gengetopt_strdup (const char *s); - -static -void clear_given (struct gengetopt_args_info *args_info) -{ - args_info->help_given = 0 ; - args_info->version_given = 0 ; - args_info->extract_given = 0 ; - args_info->long_given = 0 ; -} - -static -void clear_args (struct gengetopt_args_info *args_info) -{ - FIX_UNUSED (args_info); - args_info->extract_arg = NULL; - args_info->extract_orig = NULL; - -} - -static -void init_args_info(struct gengetopt_args_info *args_info) -{ - - - args_info->help_help = gengetopt_args_info_help[0] ; - args_info->version_help = gengetopt_args_info_help[1] ; - args_info->extract_help = gengetopt_args_info_help[2] ; - args_info->long_help = gengetopt_args_info_help[3] ; - -} - -void -cmdline_parser_print_version (void) -{ - printf ("%s %s\n", - (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), - CMDLINE_PARSER_VERSION); -} - -static void print_help_common(void) { - cmdline_parser_print_version (); - - if (strlen(gengetopt_args_info_purpose) > 0) - printf("\n%s\n", gengetopt_args_info_purpose); - - if (strlen(gengetopt_args_info_usage) > 0) - printf("\n%s\n", gengetopt_args_info_usage); - - printf("\n"); - - if (strlen(gengetopt_args_info_description) > 0) - printf("%s\n\n", gengetopt_args_info_description); -} - -void -cmdline_parser_print_help (void) -{ - int i = 0; - print_help_common(); - while (gengetopt_args_info_help[i]) - printf("%s\n", gengetopt_args_info_help[i++]); -} - -void -cmdline_parser_init (struct gengetopt_args_info *args_info) -{ - clear_given (args_info); - clear_args (args_info); - init_args_info (args_info); - - args_info->inputs = 0; - args_info->inputs_num = 0; -} - -void -cmdline_parser_params_init(struct cmdline_parser_params *params) -{ - if (params) - { - params->override = 0; - params->initialize = 1; - params->check_required = 1; - params->check_ambiguity = 0; - params->print_errors = 1; - } -} - -struct cmdline_parser_params * -cmdline_parser_params_create(void) -{ - struct cmdline_parser_params *params = - (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); - cmdline_parser_params_init(params); - return params; -} - -static void -free_string_field (char **s) -{ - if (*s) - { - free (*s); - *s = 0; - } -} - - -static void -cmdline_parser_release (struct gengetopt_args_info *args_info) -{ - unsigned int i; - free_string_field (&(args_info->extract_arg)); - free_string_field (&(args_info->extract_orig)); - - - for (i = 0; i < args_info->inputs_num; ++i) - free (args_info->inputs [i]); - - if (args_info->inputs_num) - free (args_info->inputs); - - clear_given (args_info); -} - - -static void -write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) -{ - FIX_UNUSED (values); - if (arg) { - fprintf(outfile, "%s=\"%s\"\n", opt, arg); - } else { - fprintf(outfile, "%s\n", opt); - } -} - - -int -cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) -{ - int i = 0; - - if (!outfile) - { - fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); - return EXIT_FAILURE; - } - - if (args_info->help_given) - write_into_file(outfile, "help", 0, 0 ); - if (args_info->version_given) - write_into_file(outfile, "version", 0, 0 ); - if (args_info->extract_given) - write_into_file(outfile, "extract", args_info->extract_orig, 0); - if (args_info->long_given) - write_into_file(outfile, "long", 0, 0 ); - - - i = EXIT_SUCCESS; - return i; -} - -int -cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) -{ - FILE *outfile; - int i = 0; - - outfile = fopen(filename, "w"); - - if (!outfile) - { - fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); - return EXIT_FAILURE; - } - - i = cmdline_parser_dump(outfile, args_info); - fclose (outfile); - - return i; -} - -void -cmdline_parser_free (struct gengetopt_args_info *args_info) -{ - cmdline_parser_release (args_info); -} - -/** @brief replacement of strdup, which is not standard */ -char * -gengetopt_strdup (const char *s) -{ - char *result = 0; - if (!s) - return result; - - result = (char*)malloc(strlen(s) + 1); - if (result == (char*)0) - return (char*)0; - strcpy(result, s); - return result; -} - -int -cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) -{ - return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); -} - -int -cmdline_parser_ext (int argc, char * const *argv, struct gengetopt_args_info *args_info, - struct cmdline_parser_params *params) -{ - int result; - result = cmdline_parser_internal (argc, argv, args_info, params, 0); - - if (result == EXIT_FAILURE) - { - cmdline_parser_free (args_info); - exit (EXIT_FAILURE); - } - - return result; -} - -int -cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) -{ - int result; - struct cmdline_parser_params params; - - params.override = override; - params.initialize = initialize; - params.check_required = check_required; - params.check_ambiguity = 0; - params.print_errors = 1; - - result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); - - if (result == EXIT_FAILURE) - { - cmdline_parser_free (args_info); - exit (EXIT_FAILURE); - } - - return result; -} - -int -cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) -{ - FIX_UNUSED (args_info); - FIX_UNUSED (prog_name); - return EXIT_SUCCESS; -} - -/* - * Extracted from the glibc source tree, version 2.3.6 - * - * Licensed under the GPL as per the whole glibc source tree. - * - * This file was modified so that getopt_long can be called - * many times without risking previous memory to be spoiled. - * - * Modified by Andre Noll and Lorenzo Bettini for use in - * GNU gengetopt generated files. - * - */ - -/* - * we must include anything we need since this file is not thought to be - * inserted in a file already using getopt.h - * - * Lorenzo - */ - -struct option -{ - const char *name; - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. -*/ -/* - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `custom_optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -/* Names for the values of the `has_arg' field of `struct option'. */ -#ifndef no_argument -#define no_argument 0 -#endif - -#ifndef required_argument -#define required_argument 1 -#endif - -#ifndef optional_argument -#define optional_argument 2 -#endif - -struct custom_getopt_data { - /* - * These have exactly the same meaning as the corresponding global variables, - * except that they are used for the reentrant versions of getopt. - */ - int custom_optind; - int custom_opterr; - int custom_optopt; - char *custom_optarg; - - /* True if the internal members have been initialized. */ - int initialized; - - /* - * The next char to be scanned in the option-element in which the last option - * character we returned was found. This allows us to pick up the scan where - * we left off. If this is zero, or a null string, it means resume the scan by - * advancing to the next ARGV-element. - */ - char *nextchar; - - /* - * Describe the part of ARGV that contains non-options that have been skipped. - * `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is - * the index after the last of them. - */ - int first_nonopt; - int last_nonopt; -}; - -/* - * the variables optarg, optind, opterr and optopt are renamed with - * the custom_ prefix so that they don't interfere with getopt ones. - * - * Moreover they're static so they are visible only from within the - * file where this very file will be included. - */ - -/* - * For communication from `custom_getopt' to the caller. When `custom_getopt' finds an - * option that takes an argument, the argument value is returned here. - */ -static char *custom_optarg; - -/* - * Index in ARGV of the next element to be scanned. This is used for - * communication to and from the caller and for communication between - * successive calls to `custom_getopt'. - * - * On entry to `custom_getopt', 1 means this is the first call; initialize. - * - * When `custom_getopt' returns -1, this is the index of the first of the non-option - * elements that the caller should itself scan. - * - * Otherwise, `custom_optind' communicates from one call to the next how much of ARGV - * has been scanned so far. - * - * 1003.2 says this must be 1 before any call. - */ -static int custom_optind = 1; - -/* - * Callers store zero here to inhibit the error message for unrecognized - * options. - */ -static int custom_opterr = 1; - -/* - * Set to an option character which was unrecognized. This must be initialized - * on some systems to avoid linking in the system's own getopt implementation. - */ -static int custom_optopt = '?'; - -/* - * Exchange two adjacent subsequences of ARGV. One subsequence is elements - * [first_nonopt,last_nonopt) which contains all the non-options that have been - * skipped so far. The other is elements [last_nonopt,custom_optind), which contains - * all the options processed since those non-options were skipped. - * `first_nonopt' and `last_nonopt' are relocated so that they describe the new - * indices of the non-options in ARGV after they are moved. - */ -static void exchange(char **argv, struct custom_getopt_data *d) -{ - int bottom = d->first_nonopt; - int middle = d->last_nonopt; - int top = d->custom_optind; - char *tem; - - /* - * Exchange the shorter segment with the far end of the longer segment. - * That puts the shorter segment into the right place. It leaves the - * longer segment in the right place overall, but it consists of two - * parts that need to be swapped next. - */ - while (top > middle && middle > bottom) { - if (top - middle > middle - bottom) { - /* Bottom segment is the short one. */ - int len = middle - bottom; - int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) { - tem = argv[bottom + i]; - argv[bottom + i] = - argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } else { - /* Top segment is the short one. */ - int len = top - middle; - int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - /* Update records for the slots the non-options now occupy. */ - d->first_nonopt += (d->custom_optind - d->last_nonopt); - d->last_nonopt = d->custom_optind; -} - -/* Initialize the internal data when the first call is made. */ -static void custom_getopt_initialize(struct custom_getopt_data *d) -{ - /* - * Start processing options with ARGV-element 1 (since ARGV-element 0 - * is the program name); the sequence of previously skipped non-option - * ARGV-elements is empty. - */ - d->first_nonopt = d->last_nonopt = d->custom_optind; - d->nextchar = NULL; - d->initialized = 1; -} - -#define NONOPTION_P (argv[d->custom_optind][0] != '-' || argv[d->custom_optind][1] == '\0') - -/* return: zero: continue, nonzero: return given value to user */ -static int shuffle_argv(int argc, char *const *argv,const struct option *longopts, - struct custom_getopt_data *d) -{ - /* - * Give FIRST_NONOPT & LAST_NONOPT rational values if CUSTOM_OPTIND has been - * moved back by the user (who may also have changed the arguments). - */ - if (d->last_nonopt > d->custom_optind) - d->last_nonopt = d->custom_optind; - if (d->first_nonopt > d->custom_optind) - d->first_nonopt = d->custom_optind; - /* - * If we have just processed some options following some - * non-options, exchange them so that the options come first. - */ - if (d->first_nonopt != d->last_nonopt && - d->last_nonopt != d->custom_optind) - exchange((char **) argv, d); - else if (d->last_nonopt != d->custom_optind) - d->first_nonopt = d->custom_optind; - /* - * Skip any additional non-options and extend the range of - * non-options previously skipped. - */ - while (d->custom_optind < argc && NONOPTION_P) - d->custom_optind++; - d->last_nonopt = d->custom_optind; - /* - * The special ARGV-element `--' means premature end of options. Skip - * it like a null option, then exchange with previous non-options as if - * it were an option, then skip everything else like a non-option. - */ - if (d->custom_optind != argc && !strcmp(argv[d->custom_optind], "--")) { - d->custom_optind++; - if (d->first_nonopt != d->last_nonopt - && d->last_nonopt != d->custom_optind) - exchange((char **) argv, d); - else if (d->first_nonopt == d->last_nonopt) - d->first_nonopt = d->custom_optind; - d->last_nonopt = argc; - d->custom_optind = argc; - } - /* - * If we have done all the ARGV-elements, stop the scan and back over - * any non-options that we skipped and permuted. - */ - if (d->custom_optind == argc) { - /* - * Set the next-arg-index to point at the non-options that we - * previously skipped, so the caller will digest them. - */ - if (d->first_nonopt != d->last_nonopt) - d->custom_optind = d->first_nonopt; - return -1; - } - /* - * If we have come to a non-option and did not permute it, either stop - * the scan or describe it to the caller and pass it by. - */ - if (NONOPTION_P) { - d->custom_optarg = argv[d->custom_optind++]; - return 1; - } - /* - * We have found another option-ARGV-element. Skip the initial - * punctuation. - */ - d->nextchar = (argv[d->custom_optind] + 1 + (longopts != NULL && argv[d->custom_optind][1] == '-')); - return 0; -} - -/* - * Check whether the ARGV-element is a long option. - * - * If there's a long option "fubar" and the ARGV-element is "-fu", consider - * that an abbreviation of the long option, just like "--fu", and not "-f" with - * arg "u". - * - * This distinction seems to be the most useful approach. - * - */ -static int check_long_opt(int argc, char *const *argv, const char *optstring, - const struct option *longopts, int *longind, - int print_errors, struct custom_getopt_data *d) -{ - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = d->nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match or abbreviated matches */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp(p->name, d->nextchar, nameend - d->nextchar)) { - if ((unsigned int) (nameend - d->nextchar) - == (unsigned int) strlen(p->name)) { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } else if (pfound == NULL) { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } else if (pfound->has_arg != p->has_arg - || pfound->flag != p->flag - || pfound->val != p->val) - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) { - if (print_errors) { - fprintf(stderr, - "%s: option `%s' is ambiguous\n", - argv[0], argv[d->custom_optind]); - } - d->nextchar += strlen(d->nextchar); - d->custom_optind++; - d->custom_optopt = 0; - return '?'; - } - if (pfound) { - option_index = indfound; - d->custom_optind++; - if (*nameend) { - if (pfound->has_arg != no_argument) - d->custom_optarg = nameend + 1; - else { - if (print_errors) { - if (argv[d->custom_optind - 1][1] == '-') { - /* --option */ - fprintf(stderr, "%s: option `--%s' doesn't allow an argument\n", - argv[0], pfound->name); - } else { - /* +option or -option */ - fprintf(stderr, "%s: option `%c%s' doesn't allow an argument\n", - argv[0], argv[d->custom_optind - 1][0], pfound->name); - } - - } - d->nextchar += strlen(d->nextchar); - d->custom_optopt = pfound->val; - return '?'; - } - } else if (pfound->has_arg == required_argument) { - if (d->custom_optind < argc) - d->custom_optarg = argv[d->custom_optind++]; - else { - if (print_errors) { - fprintf(stderr, - "%s: option `%s' requires an argument\n", - argv[0], - argv[d->custom_optind - 1]); - } - d->nextchar += strlen(d->nextchar); - d->custom_optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - d->nextchar += strlen(d->nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - /* - * Can't find it as a long option. If this is not getopt_long_only, or - * the option starts with '--' or is not a valid short option, then - * it's an error. Otherwise interpret it as a short option. - */ - if (print_errors) { - if (argv[d->custom_optind][1] == '-') { - /* --option */ - fprintf(stderr, - "%s: unrecognized option `--%s'\n", - argv[0], d->nextchar); - } else { - /* +option or -option */ - fprintf(stderr, - "%s: unrecognized option `%c%s'\n", - argv[0], argv[d->custom_optind][0], - d->nextchar); - } - } - d->nextchar = (char *) ""; - d->custom_optind++; - d->custom_optopt = 0; - return '?'; -} - -static int check_short_opt(int argc, char *const *argv, const char *optstring, - int print_errors, struct custom_getopt_data *d) -{ - char c = *d->nextchar++; - const char *temp = strchr(optstring, c); - - /* Increment `custom_optind' when we start to process its last character. */ - if (*d->nextchar == '\0') - ++d->custom_optind; - if (!temp || c == ':') { - if (print_errors) - fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); - - d->custom_optopt = c; - return '?'; - } - if (temp[1] == ':') { - if (temp[2] == ':') { - /* This is an option that accepts an argument optionally. */ - if (*d->nextchar != '\0') { - d->custom_optarg = d->nextchar; - d->custom_optind++; - } else - d->custom_optarg = NULL; - d->nextchar = NULL; - } else { - /* This is an option that requires an argument. */ - if (*d->nextchar != '\0') { - d->custom_optarg = d->nextchar; - /* - * If we end this ARGV-element by taking the - * rest as an arg, we must advance to the next - * element now. - */ - d->custom_optind++; - } else if (d->custom_optind == argc) { - if (print_errors) { - fprintf(stderr, - "%s: option requires an argument -- %c\n", - argv[0], c); - } - d->custom_optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } else - /* - * We already incremented `custom_optind' once; - * increment it again when taking next ARGV-elt - * as argument. - */ - d->custom_optarg = argv[d->custom_optind++]; - d->nextchar = NULL; - } - } - return c; -} - -/* - * Scan elements of ARGV for option characters given in OPTSTRING. - * - * If an element of ARGV starts with '-', and is not exactly "-" or "--", - * then it is an option element. The characters of this element - * (aside from the initial '-') are option characters. If `getopt' - * is called repeatedly, it returns successively each of the option characters - * from each of the option elements. - * - * If `getopt' finds another option character, it returns that character, - * updating `custom_optind' and `nextchar' so that the next call to `getopt' can - * resume the scan with the following option character or ARGV-element. - * - * If there are no more option characters, `getopt' returns -1. - * Then `custom_optind' is the index in ARGV of the first ARGV-element - * that is not an option. (The ARGV-elements have been permuted - * so that those that are not options now come last.) - * - * OPTSTRING is a string containing the legitimate option characters. - * If an option character is seen that is not listed in OPTSTRING, - * return '?' after printing an error message. If you set `custom_opterr' to - * zero, the error message is suppressed but we still return '?'. - * - * If a char in OPTSTRING is followed by a colon, that means it wants an arg, - * so the following text in the same ARGV-element, or the text of the following - * ARGV-element, is returned in `custom_optarg'. Two colons mean an option that - * wants an optional arg; if there is text in the current ARGV-element, - * it is returned in `custom_optarg', otherwise `custom_optarg' is set to zero. - * - * If OPTSTRING starts with `-' or `+', it requests different methods of - * handling the non-option ARGV-elements. - * See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - * - * Long-named options begin with `--' instead of `-'. - * Their names may be abbreviated as long as the abbreviation is unique - * or is an exact match for some defined option. If they have an - * argument, it follows the option name in the same ARGV-element, separated - * from the option name by a `=', or else the in next ARGV-element. - * When `getopt' finds a long-named option, it returns 0 if that option's - * `flag' field is nonzero, the value of the option's `val' field - * if the `flag' field is zero. - * - * The elements of ARGV aren't really const, because we permute them. - * But we pretend they're const in the prototype to be compatible - * with other systems. - * - * LONGOPTS is a vector of `struct option' terminated by an - * element containing a name which is zero. - * - * LONGIND returns the index in LONGOPT of the long-named option found. - * It is only valid when a long-named option has been found by the most - * recent call. - * - * Return the option character from OPTS just read. Return -1 when there are - * no more options. For unrecognized options, or options missing arguments, - * `custom_optopt' is set to the option letter, and '?' is returned. - * - * The OPTS string is a list of characters which are recognized option letters, - * optionally followed by colons, specifying that that letter takes an - * argument, to be placed in `custom_optarg'. - * - * If a letter in OPTS is followed by two colons, its argument is optional. - * This behavior is specific to the GNU `getopt'. - * - * The argument `--' causes premature termination of argument scanning, - * explicitly telling `getopt' that there are no more options. If OPTS begins - * with `--', then non-option arguments are treated as arguments to the option - * '\0'. This behavior is specific to the GNU `getopt'. - */ - -static int getopt_internal_r(int argc, char *const *argv, const char *optstring, - const struct option *longopts, int *longind, - struct custom_getopt_data *d) -{ - int ret, print_errors = d->custom_opterr; - - if (optstring[0] == ':') - print_errors = 0; - if (argc < 1) - return -1; - d->custom_optarg = NULL; - - /* - * This is a big difference with GNU getopt, since optind == 0 - * means initialization while here 1 means first call. - */ - if (d->custom_optind == 0 || !d->initialized) { - if (d->custom_optind == 0) - d->custom_optind = 1; /* Don't scan ARGV[0], the program name. */ - custom_getopt_initialize(d); - } - if (d->nextchar == NULL || *d->nextchar == '\0') { - ret = shuffle_argv(argc, argv, longopts, d); - if (ret) - return ret; - } - if (longopts && (argv[d->custom_optind][1] == '-' )) - return check_long_opt(argc, argv, optstring, longopts, - longind, print_errors, d); - return check_short_opt(argc, argv, optstring, print_errors, d); -} - -static int custom_getopt_internal(int argc, char *const *argv, const char *optstring, - const struct option *longopts, int *longind) -{ - int result; - /* Keep a global copy of all internal members of d */ - static struct custom_getopt_data d; - - d.custom_optind = custom_optind; - d.custom_opterr = custom_opterr; - result = getopt_internal_r(argc, argv, optstring, longopts, - longind, &d); - custom_optind = d.custom_optind; - custom_optarg = d.custom_optarg; - custom_optopt = d.custom_optopt; - return result; -} - -static int custom_getopt_long (int argc, char *const *argv, const char *options, - const struct option *long_options, int *opt_index) -{ - return custom_getopt_internal(argc, argv, options, long_options, - opt_index); -} - - -static char *package_name = 0; - -/** - * @brief updates an option - * @param field the generic pointer to the field to update - * @param orig_field the pointer to the orig field - * @param field_given the pointer to the number of occurrence of this option - * @param prev_given the pointer to the number of occurrence already seen - * @param value the argument for this option (if null no arg was specified) - * @param possible_values the possible values for this option (if specified) - * @param default_value the default value (in case the option only accepts fixed values) - * @param arg_type the type of this option - * @param check_ambiguity @see cmdline_parser_params.check_ambiguity - * @param override @see cmdline_parser_params.override - * @param no_free whether to free a possible previous value - * @param multiple_option whether this is a multiple option - * @param long_opt the corresponding long option - * @param short_opt the corresponding short option (or '-' if none) - * @param additional_error possible further error specification - */ -static -int update_arg(void *field, char **orig_field, - unsigned int *field_given, unsigned int *prev_given, - char *value, const char *possible_values[], - const char *default_value, - cmdline_parser_arg_type arg_type, - int check_ambiguity, int override, - int no_free, int multiple_option, - const char *long_opt, char short_opt, - const char *additional_error) -{ - FIX_UNUSED (field); - char *stop_char = 0; - const char *val = value; - int found; - char **string_field; - - stop_char = 0; - found = 0; - - if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) - { - if (short_opt != '-') - fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", - package_name, long_opt, short_opt, - (additional_error ? additional_error : "")); - else - fprintf (stderr, "%s: `--%s' option given more than once%s\n", - package_name, long_opt, - (additional_error ? additional_error : "")); - return 1; /* failure */ - } - - FIX_UNUSED (default_value); - - if (field_given && *field_given && ! override) - return 0; - if (prev_given) - (*prev_given)++; - if (field_given) - (*field_given)++; - if (possible_values) - val = possible_values[found]; - - switch(arg_type) { - case ARG_STRING: - if (val) { - string_field = (char **)field; - if (!no_free && *string_field) - free (*string_field); /* free previous string */ - *string_field = gengetopt_strdup (val); - } - break; - default: - break; - }; - - - /* store the original value */ - switch(arg_type) { - case ARG_NO: - break; - default: - if (value && orig_field) { - if (no_free) { - *orig_field = value; - } else { - if (*orig_field) - free (*orig_field); /* free previous string */ - *orig_field = gengetopt_strdup (value); - } - } - }; - - return 0; /* OK */ -} - - -int -cmdline_parser_internal ( - int argc, char * const *argv, struct gengetopt_args_info *args_info, - struct cmdline_parser_params *params, const char *additional_error) -{ - int c; /* Character of the parsed option. */ - - int error = 0; - struct gengetopt_args_info local_args_info; - - int override; - int initialize; - int check_required; - int check_ambiguity; - - char *optarg; - int optind; - int opterr; - int optopt; - - package_name = argv[0]; - - override = params->override; - initialize = params->initialize; - check_required = params->check_required; - check_ambiguity = params->check_ambiguity; - - if (initialize) - cmdline_parser_init (args_info); - - cmdline_parser_init (&local_args_info); - - optarg = 0; - optind = 0; - opterr = params->print_errors; - optopt = '?'; - - while (1) - { - int option_index = 0; - - static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "extract", 1, NULL, 'x' }, - { "long", 0, NULL, 'l' }, - { 0, 0, 0, 0 } - }; - - custom_optarg = optarg; - custom_optind = optind; - custom_opterr = opterr; - custom_optopt = optopt; - - c = custom_getopt_long (argc, argv, "hVx:l", long_options, &option_index); - - optarg = custom_optarg; - optind = custom_optind; - opterr = custom_opterr; - optopt = custom_optopt; - - if (c == -1) break; /* Exit from `while (1)' loop. */ - - switch (c) - { - case 'h': /* Print help and exit. */ - cmdline_parser_print_help (); - cmdline_parser_free (&local_args_info); - exit (EXIT_SUCCESS); - - case 'V': /* Print version and exit. */ - cmdline_parser_print_version (); - cmdline_parser_free (&local_args_info); - exit (EXIT_SUCCESS); - - case 'x': /* Extract file from archive. */ - - - if (update_arg( (void *)&(args_info->extract_arg), - &(args_info->extract_orig), &(args_info->extract_given), - &(local_args_info.extract_given), optarg, 0, 0, ARG_STRING, - check_ambiguity, override, 0, 0, - "extract", 'x', - additional_error)) - goto failure; - - break; - case 'l': /* Include extra information in archive listing. */ - - - if (update_arg( 0 , - 0 , &(args_info->long_given), - &(local_args_info.long_given), optarg, 0, 0, ARG_NO, - check_ambiguity, override, 0, 0, - "long", 'l', - additional_error)) - goto failure; - - break; - - case 0: /* Long option with no short option */ - case '?': /* Invalid option. */ - /* `getopt_long' already printed an error message. */ - goto failure; - - default: /* bug: option not considered. */ - fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); - abort (); - } /* switch */ - } /* while */ - - - - - cmdline_parser_release (&local_args_info); - - if ( error ) - return (EXIT_FAILURE); - - if (optind < argc) - { - int i = 0 ; - int found_prog_name = 0; - /* whether program name, i.e., argv[0], is in the remaining args - (this may happen with some implementations of getopt, - but surely not with the one included by gengetopt) */ - - - args_info->inputs_num = argc - optind - found_prog_name; - args_info->inputs = - (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ; - while (optind < argc) - args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind++]) ; - } - - return 0; - -failure: - - cmdline_parser_release (&local_args_info); - return (EXIT_FAILURE); -} diff --git a/apps/bsatool/bsatool_cmd.h b/apps/bsatool/bsatool_cmd.h deleted file mode 100644 index 4d5f80ea2..000000000 --- a/apps/bsatool/bsatool_cmd.h +++ /dev/null @@ -1,179 +0,0 @@ -/** @file bsatool_cmd.h - * @brief The header file for the command line option parser - * generated by GNU Gengetopt version 2.22.2 - * http://www.gnu.org/software/gengetopt. - * DO NOT modify this file, since it can be overwritten - * @author GNU Gengetopt by Lorenzo Bettini */ - -#ifndef BSATOOL_CMD_H -#define BSATOOL_CMD_H - -/* If we use autoconf. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include /* for FILE */ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef CMDLINE_PARSER_PACKAGE -/** @brief the program name (used for printing errors) */ -#define CMDLINE_PARSER_PACKAGE "bsatool" -#endif - -#ifndef CMDLINE_PARSER_PACKAGE_NAME -/** @brief the complete program name (used for help and version) */ -#define CMDLINE_PARSER_PACKAGE_NAME "bsatool" -#endif - -#ifndef CMDLINE_PARSER_VERSION -/** @brief the program version */ -#define CMDLINE_PARSER_VERSION "1.0" -#endif - -/** @brief Where the command line options are stored */ -struct gengetopt_args_info -{ - const char *help_help; /**< @brief Print help and exit help description. */ - const char *version_help; /**< @brief Print version and exit help description. */ - char * extract_arg; /**< @brief Extract file from archive. */ - char * extract_orig; /**< @brief Extract file from archive original value given at command line. */ - const char *extract_help; /**< @brief Extract file from archive help description. */ - const char *long_help; /**< @brief Include extra information in archive listing help description. */ - - unsigned int help_given ; /**< @brief Whether help was given. */ - unsigned int version_given ; /**< @brief Whether version was given. */ - unsigned int extract_given ; /**< @brief Whether extract was given. */ - unsigned int long_given ; /**< @brief Whether long was given. */ - - char **inputs ; /**< @brief unamed options (options without names) */ - unsigned inputs_num ; /**< @brief unamed options number */ -} ; - -/** @brief The additional parameters to pass to parser functions */ -struct cmdline_parser_params -{ - int override; /**< @brief whether to override possibly already present options (default 0) */ - int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ - int check_required; /**< @brief whether to check that all required options were provided (default 1) */ - int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ - int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ -} ; - -/** @brief the purpose string of the program */ -extern const char *gengetopt_args_info_purpose; -/** @brief the usage string of the program */ -extern const char *gengetopt_args_info_usage; -/** @brief all the lines making the help output */ -extern const char *gengetopt_args_info_help[]; - -/** - * The command line parser - * @param argc the number of command line options - * @param argv the command line options - * @param args_info the structure where option information will be stored - * @return 0 if everything went fine, NON 0 if an error took place - */ -int cmdline_parser (int argc, char * const *argv, - struct gengetopt_args_info *args_info); - -/** - * The command line parser (version with additional parameters - deprecated) - * @param argc the number of command line options - * @param argv the command line options - * @param args_info the structure where option information will be stored - * @param override whether to override possibly already present options - * @param initialize whether to initialize the option structure my_args_info - * @param check_required whether to check that all required options were provided - * @return 0 if everything went fine, NON 0 if an error took place - * @deprecated use cmdline_parser_ext() instead - */ -int cmdline_parser2 (int argc, char * const *argv, - struct gengetopt_args_info *args_info, - int override, int initialize, int check_required); - -/** - * The command line parser (version with additional parameters) - * @param argc the number of command line options - * @param argv the command line options - * @param args_info the structure where option information will be stored - * @param params additional parameters for the parser - * @return 0 if everything went fine, NON 0 if an error took place - */ -int cmdline_parser_ext (int argc, char * const *argv, - struct gengetopt_args_info *args_info, - struct cmdline_parser_params *params); - -/** - * Save the contents of the option struct into an already open FILE stream. - * @param outfile the stream where to dump options - * @param args_info the option struct to dump - * @return 0 if everything went fine, NON 0 if an error took place - */ -int cmdline_parser_dump(FILE *outfile, - struct gengetopt_args_info *args_info); - -/** - * Save the contents of the option struct into a (text) file. - * This file can be read by the config file parser (if generated by gengetopt) - * @param filename the file where to save - * @param args_info the option struct to save - * @return 0 if everything went fine, NON 0 if an error took place - */ -int cmdline_parser_file_save(const char *filename, - struct gengetopt_args_info *args_info); - -/** - * Print the help - */ -void cmdline_parser_print_help(void); -/** - * Print the version - */ -void cmdline_parser_print_version(void); - -/** - * Initializes all the fields a cmdline_parser_params structure - * to their default values - * @param params the structure to initialize - */ -void cmdline_parser_params_init(struct cmdline_parser_params *params); - -/** - * Allocates dynamically a cmdline_parser_params structure and initializes - * all its fields to their default values - * @return the created and initialized cmdline_parser_params structure - */ -struct cmdline_parser_params *cmdline_parser_params_create(void); - -/** - * Initializes the passed gengetopt_args_info structure's fields - * (also set default values for options that have a default) - * @param args_info the structure to initialize - */ -void cmdline_parser_init (struct gengetopt_args_info *args_info); -/** - * Deallocates the string fields of the gengetopt_args_info structure - * (but does not deallocate the structure itself) - * @param args_info the structure to deallocate - */ -void cmdline_parser_free (struct gengetopt_args_info *args_info); - -/** - * Checks that all the required options were specified - * @param args_info the structure to check - * @param prog_name the name of the program that will be used to print - * possible errors - * @return - */ -int cmdline_parser_required (struct gengetopt_args_info *args_info, - const char *prog_name); - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* BSATOOL_CMD_H */ From d696da767762739af746c255a45c1a8040950225 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 7 Mar 2013 21:38:27 +0100 Subject: [PATCH 915/916] Fix selection buffer --- libs/openengine/ogre/selectionbuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index c6b43a45d..30e7b9e1e 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -24,7 +24,8 @@ namespace Render vp->setBackgroundColour(Ogre::ColourValue(0, 0, 0, 0)); vp->setShadowsEnabled(false); vp->setMaterialScheme("selectionbuffer"); - vp->setVisibilityMask (visibilityFlags); + if (visibilityFlags != 0) + vp->setVisibilityMask (visibilityFlags); mRenderTarget->setActive(true); mRenderTarget->setAutoUpdated (false); From 285b4bf726448722a2390260280925600b23c56f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 8 Mar 2013 00:12:56 +0100 Subject: [PATCH 916/916] Allow zooming camera in vanity or preview mode with the mousewheel --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 3 +++ apps/openmw/mwrender/player.cpp | 7 +++++++ apps/openmw/mwrender/player.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.hpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 4 ++++ 6 files changed, 22 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 654a59cea..6cd5b90b4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -296,6 +296,7 @@ namespace MWBase virtual bool toggleVanityMode(bool enable, bool force) = 0; virtual void allowVanityMode(bool allow) = 0; virtual void togglePlayerLooking(bool enable) = 0; + virtual void changeVanityModeScale(float factor) = 0; virtual void renderPlayer() = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4c10749b3..f18c02a0e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -548,6 +548,9 @@ namespace MWInput MWBase::World *world = MWBase::Environment::get().getWorld(); world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); + + if (arg.state.Z.rel) + MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); } return true; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 1ac3b072f..63396378d 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -271,6 +271,8 @@ namespace MWRender v.z = 800.f; } else if (v.z < 10.f) { v.z = 10.f; + } else if (override && v.z < 50.f) { + v.z = 50.f; } mCamera->setPosition(v); @@ -362,4 +364,9 @@ namespace MWRender mCameraNode->setPosition(0.f, 0.f, mHeight); } } + + bool Player::isVanityOrPreviewModeEnabled() + { + return mPreviewMode || mVanity.enabled; + } } diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index e24f44d68..9de41823d 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -110,6 +110,8 @@ namespace MWRender void getSightAngles(float &pitch, float &yaw); void togglePlayerLooking(bool enable); + + bool isVanityOrPreviewModeEnabled(); }; } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 5cea24175..1777a72c3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -83,6 +83,11 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList mPlayer->togglePlayerLooking(enable); } + void changeVanityModeScale(float factor) { + if (mPlayer->isVanityOrPreviewModeEnabled()) + mPlayer->setCameraDistance(-factor/120.f*10, true, true); + } + void getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw); void attachCameraTo(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 47088aa62..fe4ceff69 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -339,6 +339,10 @@ namespace MWWorld mRendering->togglePlayerLooking(enable); } + virtual void changeVanityModeScale(float factor) { + mRendering->changeVanityModeScale(factor); + } + virtual void renderPlayer(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);