From 414f7ea02cea63ac239fa480d189090dcbcb9fb2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 19 Nov 2014 12:09:40 +0100 Subject: [PATCH 01/98] Ignore mouse movements during video playback (Fixes #2139) --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 29b166a6a..6cb3a5ec5 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -603,7 +603,7 @@ namespace MWInput MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); } - if (mMouseLookEnabled) + if (mMouseLookEnabled && !mControlsDisabled) { resetIdleTime(); From a0c454b01c711a57cde3363e98f9fb5c44ac58dc Mon Sep 17 00:00:00 2001 From: Nikolay Kasyanov Date: Sat, 22 Nov 2014 22:53:01 +0200 Subject: [PATCH 02/98] Properly add libunshiled include dir (again, for wizard this time) --- apps/wizard/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index f2defd031..8e9ea8d0e 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -82,7 +82,7 @@ QT4_WRAP_UI(UI_HDRS ${WIZARD_UI}) include(${QT_USE_FILE}) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${LIBUNSHIELD_INCLUDE}) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${LIBUNSHIELD_INCLUDE_DIR}) add_executable(openmw-wizard ${GUI_TYPE} From a8a2b44b0fe52df0dbef027c3ac2b8eba38e01fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 23 Nov 2014 00:51:57 +0100 Subject: [PATCH 03/98] Don't require libunshield on windows --- CMakeLists.txt | 5 ---- apps/wizard/CMakeLists.txt | 42 ++++++++++++++++++++--------- apps/wizard/mainwizard.cpp | 2 ++ apps/wizard/methodselectionpage.cpp | 5 ++++ 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 208bddf33..5a923c631 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -600,11 +600,6 @@ if (BUILD_OPENCS) endif() if (BUILD_WIZARD) - find_package(LIBUNSHIELD REQUIRED) - if(NOT LIBUNSHIELD_FOUND) - message(FATAL_ERROR "Failed to find Unshield library") - endif(NOT LIBUNSHIELD_FOUND) - add_subdirectory(apps/wizard) endif() diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index f2defd031..76ca648db 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -1,10 +1,20 @@ +if (WIN32) # windows users can just run the morrowind installer + set(OPENMW_USE_UNSHIELD FALSE) +else() + set(OPENMW_USE_UNSHIELD TRUE) + + find_package(LIBUNSHIELD REQUIRED) + if(NOT LIBUNSHIELD_FOUND) + message(FATAL_ERROR "Failed to find Unshield library") + endif(NOT LIBUNSHIELD_FOUND) +endif() + set(WIZARD componentselectionpage.cpp conclusionpage.cpp existinginstallationpage.cpp importpage.cpp inisettings.cpp - installationpage.cpp installationtargetpage.cpp intropage.cpp languageselectionpage.cpp @@ -12,8 +22,6 @@ set(WIZARD mainwizard.cpp methodselectionpage.cpp - unshield/unshieldworker.cpp - utils/componentlistwidget.cpp ) @@ -23,15 +31,12 @@ set(WIZARD_HEADER existinginstallationpage.hpp importpage.hpp inisettings.hpp - installationpage.hpp installationtargetpage.hpp intropage.hpp languageselectionpage.hpp mainwizard.hpp methodselectionpage.hpp - unshield/unshieldworker.hpp - utils/componentlistwidget.hpp ) @@ -41,15 +46,12 @@ set(WIZARD_HEADER_MOC conclusionpage.hpp existinginstallationpage.hpp importpage.hpp - installationpage.hpp installationtargetpage.hpp intropage.hpp languageselectionpage.hpp mainwizard.hpp methodselectionpage.hpp - unshield/unshieldworker.hpp - utils/componentlistwidget.hpp ) @@ -58,13 +60,21 @@ set(WIZARD_UI ${CMAKE_SOURCE_DIR}/files/ui/wizard/conclusionpage.ui ${CMAKE_SOURCE_DIR}/files/ui/wizard/existinginstallationpage.ui ${CMAKE_SOURCE_DIR}/files/ui/wizard/importpage.ui - ${CMAKE_SOURCE_DIR}/files/ui/wizard/installationpage.ui ${CMAKE_SOURCE_DIR}/files/ui/wizard/installationtargetpage.ui ${CMAKE_SOURCE_DIR}/files/ui/wizard/intropage.ui ${CMAKE_SOURCE_DIR}/files/ui/wizard/languageselectionpage.ui ${CMAKE_SOURCE_DIR}/files/ui/wizard/methodselectionpage.ui ) +if (OPENMW_USE_UNSHIELD) + set (WIZARD ${WIZARD} installationpage.cpp unshield/unshieldworker.cpp) + set (WIZARD_HEADER ${WIZARD_HEADER} installationpage.hpp unshield/unshieldworker.hpp) + set (WIZARD_HEADER_MOC ${WIZARD_HEADER_MOC} installationpage.hpp unshield/unshieldworker.hpp) + set (WIZARD_UI ${WIZARD_UI} ${CMAKE_SOURCE_DIR}/files/ui/wizard/installationpage.ui) + add_definitions(-DOPENMW_USE_UNSHIELD) +endif (OPENMW_USE_UNSHIELD) + + source_group(wizard FILES ${WIZARD} ${WIZARD_HEADER}) find_package(Qt4 REQUIRED) @@ -82,7 +92,11 @@ QT4_WRAP_UI(UI_HDRS ${WIZARD_UI}) include(${QT_USE_FILE}) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${LIBUNSHIELD_INCLUDE}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +if (OPENMW_USE_UNSHIELD) + include_directories(${LIBUNSHIELD_INCLUDE}) +endif() add_executable(openmw-wizard ${GUI_TYPE} @@ -96,10 +110,14 @@ add_executable(openmw-wizard target_link_libraries(openmw-wizard ${Boost_LIBRARIES} ${QT_LIBRARIES} - ${LIBUNSHIELD_LIBRARY} components ) +if (OPENMW_USE_UNSHIELD) + target_link_libraries(openmw-wizard ${LIBUNSHIELD_LIBRARY}) +endif() + + if(DPKG_PROGRAM) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION games COMPONENT openmw-wizard) endif() diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index d539793ec..f98aae315 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -322,7 +322,9 @@ void Wizard::MainWizard::setupPages() setPage(Page_ExistingInstallation, new ExistingInstallationPage(this)); setPage(Page_InstallationTarget, new InstallationTargetPage(this, mCfgMgr)); setPage(Page_ComponentSelection, new ComponentSelectionPage(this)); +#ifdef OPENMW_USE_UNSHIELD setPage(Page_Installation, new InstallationPage(this)); +#endif setPage(Page_Import, new ImportPage(this)); setPage(Page_Conclusion, new ConclusionPage(this)); setStartId(Page_Intro); diff --git a/apps/wizard/methodselectionpage.cpp b/apps/wizard/methodselectionpage.cpp index d7c64f3b0..5f3917bd5 100644 --- a/apps/wizard/methodselectionpage.cpp +++ b/apps/wizard/methodselectionpage.cpp @@ -9,6 +9,11 @@ Wizard::MethodSelectionPage::MethodSelectionPage(QWidget *parent) : setupUi(this); +#ifndef OPENMW_USE_UNSHIELD + newLocationRadioButton->setEnabled(false); + existingLocationRadioButton->setChecked(true); +#endif + registerField(QLatin1String("installation.new"), newLocationRadioButton); } From abf49267ea1ed1e79b8774dec8023b18aa5a85ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 23 Nov 2014 13:44:03 +0100 Subject: [PATCH 04/98] Unshield include fix --- apps/wizard/mainwizard.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index f98aae315..e68070c4d 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -15,10 +15,13 @@ #include "existinginstallationpage.hpp" #include "installationtargetpage.hpp" #include "componentselectionpage.hpp" -#include "installationpage.hpp" #include "importpage.hpp" #include "conclusionpage.hpp" +#ifdef OPENMW_USE_UNSHIELD +#include "installationpage.hpp" +#endif + using namespace Process; Wizard::MainWizard::MainWizard(QWidget *parent) : From c9e7a41e1a77e18e810e1e3a0e67b1a0a9c401c3 Mon Sep 17 00:00:00 2001 From: Sergey Shnatsel Davidoff Date: Sun, 23 Nov 2014 17:39:01 +0300 Subject: [PATCH 05/98] Add my scene view icons: status overview icons, element toggle icons, parts from which they're assembled and the SVG master. --- .../scene-view-parts/0_sky_backdrop.png | Bin 0 -> 216 bytes .../raster/scene-view-parts/10_bridge.png | Bin 0 -> 1848 bytes .../scene-view-parts/11_terrain_front.png | Bin 0 -> 1215 bytes .../scene-view-parts/12_water_front.png | Bin 0 -> 593 bytes .../raster/scene-view-parts/13_pathgrid.png | Bin 0 -> 751 bytes .../raster/scene-view-parts/14_divider.png | Bin 0 -> 224 bytes .../1_terrain_very_distant.png | Bin 0 -> 906 bytes .../scene-view-parts/2_fog_very_distant.png | Bin 0 -> 334 bytes .../scene-view-parts/3_water_backdrop.png | Bin 0 -> 824 bytes .../scene-view-parts/4_water_distant.png | Bin 0 -> 668 bytes .../scene-view-parts/5_terrain_distant.png | Bin 0 -> 1152 bytes .../raster/scene-view-parts/6_fog_distant.png | Bin 0 -> 1541 bytes .../scene-view-parts/7_terrain_back.png | Bin 0 -> 1567 bytes .../raster/scene-view-parts/8_water_back.png | Bin 0 -> 638 bytes .../raster/scene-view-parts/9_fog_back.png | Bin 0 -> 1426 bytes files/opencs/raster/scene-view-parts/README | 10 + .../composite_the_32_icons.sh | 21 + files/opencs/raster/scene-view-parts/mask.png | Bin 0 -> 3419 bytes .../scalable/scene-view-status-rev14.svg | 923 ++++++++++++++++++ files/opencs/scene-view-fog.png | Bin 0 -> 962 bytes files/opencs/scene-view-pathgrid.png | Bin 0 -> 640 bytes files/opencs/scene-view-references.png | Bin 0 -> 1785 bytes files/opencs/scene-view-status-0.png | Bin 0 -> 2029 bytes files/opencs/scene-view-status-1.png | Bin 0 -> 2787 bytes files/opencs/scene-view-status-10.png | Bin 0 -> 2589 bytes files/opencs/scene-view-status-11.png | Bin 0 -> 3186 bytes files/opencs/scene-view-status-12.png | Bin 0 -> 3025 bytes files/opencs/scene-view-status-13.png | Bin 0 -> 3279 bytes files/opencs/scene-view-status-14.png | Bin 0 -> 3133 bytes files/opencs/scene-view-status-15.png | Bin 0 -> 3354 bytes files/opencs/scene-view-status-16.png | Bin 0 -> 3078 bytes files/opencs/scene-view-status-17.png | Bin 0 -> 3265 bytes files/opencs/scene-view-status-18.png | Bin 0 -> 3201 bytes files/opencs/scene-view-status-19.png | Bin 0 -> 3327 bytes files/opencs/scene-view-status-2.png | Bin 0 -> 2296 bytes files/opencs/scene-view-status-20.png | Bin 0 -> 3256 bytes files/opencs/scene-view-status-21.png | Bin 0 -> 3398 bytes files/opencs/scene-view-status-22.png | Bin 0 -> 3389 bytes files/opencs/scene-view-status-23.png | Bin 0 -> 3464 bytes files/opencs/scene-view-status-24.png | Bin 0 -> 3249 bytes files/opencs/scene-view-status-25.png | Bin 0 -> 3355 bytes files/opencs/scene-view-status-26.png | Bin 0 -> 3351 bytes files/opencs/scene-view-status-27.png | Bin 0 -> 3426 bytes files/opencs/scene-view-status-28.png | Bin 0 -> 3388 bytes files/opencs/scene-view-status-29.png | Bin 0 -> 3491 bytes files/opencs/scene-view-status-3.png | Bin 0 -> 2927 bytes files/opencs/scene-view-status-30.png | Bin 0 -> 3489 bytes files/opencs/scene-view-status-31.png | Bin 0 -> 3553 bytes files/opencs/scene-view-status-4.png | Bin 0 -> 2708 bytes files/opencs/scene-view-status-5.png | Bin 0 -> 3049 bytes files/opencs/scene-view-status-6.png | Bin 0 -> 2877 bytes files/opencs/scene-view-status-7.png | Bin 0 -> 3144 bytes files/opencs/scene-view-status-8.png | Bin 0 -> 2432 bytes files/opencs/scene-view-status-9.png | Bin 0 -> 3096 bytes files/opencs/scene-view-terrain.png | Bin 0 -> 2490 bytes files/opencs/scene-view-water.png | Bin 0 -> 1066 bytes 56 files changed, 954 insertions(+) create mode 100644 files/opencs/raster/scene-view-parts/0_sky_backdrop.png create mode 100644 files/opencs/raster/scene-view-parts/10_bridge.png create mode 100644 files/opencs/raster/scene-view-parts/11_terrain_front.png create mode 100644 files/opencs/raster/scene-view-parts/12_water_front.png create mode 100644 files/opencs/raster/scene-view-parts/13_pathgrid.png create mode 100644 files/opencs/raster/scene-view-parts/14_divider.png create mode 100644 files/opencs/raster/scene-view-parts/1_terrain_very_distant.png create mode 100644 files/opencs/raster/scene-view-parts/2_fog_very_distant.png create mode 100644 files/opencs/raster/scene-view-parts/3_water_backdrop.png create mode 100644 files/opencs/raster/scene-view-parts/4_water_distant.png create mode 100644 files/opencs/raster/scene-view-parts/5_terrain_distant.png create mode 100644 files/opencs/raster/scene-view-parts/6_fog_distant.png create mode 100644 files/opencs/raster/scene-view-parts/7_terrain_back.png create mode 100644 files/opencs/raster/scene-view-parts/8_water_back.png create mode 100644 files/opencs/raster/scene-view-parts/9_fog_back.png create mode 100644 files/opencs/raster/scene-view-parts/README create mode 100755 files/opencs/raster/scene-view-parts/composite_the_32_icons.sh create mode 100644 files/opencs/raster/scene-view-parts/mask.png create mode 100644 files/opencs/scalable/scene-view-status-rev14.svg create mode 100644 files/opencs/scene-view-fog.png create mode 100644 files/opencs/scene-view-pathgrid.png create mode 100644 files/opencs/scene-view-references.png create mode 100644 files/opencs/scene-view-status-0.png create mode 100644 files/opencs/scene-view-status-1.png create mode 100644 files/opencs/scene-view-status-10.png create mode 100644 files/opencs/scene-view-status-11.png create mode 100644 files/opencs/scene-view-status-12.png create mode 100644 files/opencs/scene-view-status-13.png create mode 100644 files/opencs/scene-view-status-14.png create mode 100644 files/opencs/scene-view-status-15.png create mode 100644 files/opencs/scene-view-status-16.png create mode 100644 files/opencs/scene-view-status-17.png create mode 100644 files/opencs/scene-view-status-18.png create mode 100644 files/opencs/scene-view-status-19.png create mode 100644 files/opencs/scene-view-status-2.png create mode 100644 files/opencs/scene-view-status-20.png create mode 100644 files/opencs/scene-view-status-21.png create mode 100644 files/opencs/scene-view-status-22.png create mode 100644 files/opencs/scene-view-status-23.png create mode 100644 files/opencs/scene-view-status-24.png create mode 100644 files/opencs/scene-view-status-25.png create mode 100644 files/opencs/scene-view-status-26.png create mode 100644 files/opencs/scene-view-status-27.png create mode 100644 files/opencs/scene-view-status-28.png create mode 100644 files/opencs/scene-view-status-29.png create mode 100644 files/opencs/scene-view-status-3.png create mode 100644 files/opencs/scene-view-status-30.png create mode 100644 files/opencs/scene-view-status-31.png create mode 100644 files/opencs/scene-view-status-4.png create mode 100644 files/opencs/scene-view-status-5.png create mode 100644 files/opencs/scene-view-status-6.png create mode 100644 files/opencs/scene-view-status-7.png create mode 100644 files/opencs/scene-view-status-8.png create mode 100644 files/opencs/scene-view-status-9.png create mode 100644 files/opencs/scene-view-terrain.png create mode 100644 files/opencs/scene-view-water.png diff --git a/files/opencs/raster/scene-view-parts/0_sky_backdrop.png b/files/opencs/raster/scene-view-parts/0_sky_backdrop.png new file mode 100644 index 0000000000000000000000000000000000000000..f215662fc472efd87778863ff81ac9bddcf9ac64 GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt-XRE{-7? zjc?C8@*YrNIN;!*V)XHNw(!Q|sh<9h*57xY|FLl?^S&&HY!YBK=& Nc)I$ztaD0e0su}cLV5rI literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/10_bridge.png b/files/opencs/raster/scene-view-parts/10_bridge.png new file mode 100644 index 0000000000000000000000000000000000000000..1c9fd34f99579855652050151c8c95236225175c GIT binary patch literal 1848 zcmV-82gmq{P)$WJ6O#%eyrrs6kszuvXmsu1rx+vNtuno0R9N0+%$&w{gq9yBVeJoM7 z6Fy2L-+XQteDCQ!lA;l}01T~z+Dnaz&(9QJEd5=G^_7rgLTz5Rt)IPX>U;B$E`+A#+2!aGa z1VIGyl@bvGe06{V3fSRUqQPKeoH~02%rMMgHZaW4S|c?(_g3tBxadA!T=!9oZWZHe2{X&mqALGRHc)yX^GgZ2_2QCcg0fqsI9 z&8`UJw@m4IseM<(b0_*C1Yvx78Uv?KL6psqXQ7`azq??VkGT!cpXkR?FY`YC3*iu? zpeV1+wsOo(K4MTIZ9n+Wd8OW8>n3&CI1AegCCI$G&}FW~{8Q zVRAZsUn%ph09mP-nLpXKefmh(VR8kymIJ_6TR{W_D5X5RghC+@6P8w1Ev3|ZgV*m| z0f39=2Y$79|Nh^4x;xv52y^obMF4-eI&}Mz6K3k-g|nf%_vSu$>Fk-f8+$yJ$||Yf z9{g^|C6tmdYy_I45BnrE_FtWJLP=ee~JHV`dI1 zC84AQ0P>IJTpw6#1+6q}X@?|*4qh9ch+G+(==|i9*#nR$yD(fSt&r52IZQWwY^dct{tm_IS^lIQ+ozd zZ@#%Fp}i1^gaeszV;Ez+QcmP)q2fUcRa~btnG8jC?`Hr2+txJ)k4A$Qa$`uP2*BD`M8(tgpR5QTvALvw(g$eo8GR&A-BHq=MDIW)9T@VCG5#>u8^HWckBwCXiLmR}LR37#}o mGTGNGWm9CYv8oFAHsQZUpEj1=M literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/11_terrain_front.png b/files/opencs/raster/scene-view-parts/11_terrain_front.png new file mode 100644 index 0000000000000000000000000000000000000000..adab37570666a78a452d2691633e8037e5898c7f GIT binary patch literal 1215 zcmV;w1VHz;dKa?u1E3)_SgHt|t}oQUM+ z-o%io7y=?%*hImAm4AU?p{1Qw8k>k$VwI3W2ob?r1i?a4keJ-ZdCbgS7PHTsb5Eie zqZtD88x9PMIWxa+ug4x3F*6=!Y1;HykS2hg@UfVR~Ew5<-HZFK-`s{?3T z9YEXa0NPdu(6%~&w$%Z&tq!1VJ@f#wdhE!%z~h+RM&t_c-TLJ#+ie@Wo7PtPDX<^2 zqX_#zev`9jj+u*;aZxcWN~s4v5GH2ropcQ5ri*lZdi1 zHNEW=2s~+}a#+duxQ5zhubi^~+aU`wDVmrT-zqg{6g59$Cyu;s_N%1Vp3; z@Mf5=0lXPzP*t8^Z*Ec))lY^UT)%wv)`K*@w$e`pu0@d^+PAz&>>@-6<^@qfMbNPP z7}URz4H4M8r$?T}Pl(9(q5d9}c@?;kChpL_C1xv5cu3VJ-BCA4oKq)LP`>)NvxO((C75Uw{ z=-K6^OklXERUEY2w48WNTRBBK;!Il9w)i_T~6~jGudXRknxY zkIKrwy^uP|64x}UYM3-4)8?IvyV;b~Wc9&(xhxCv~AOy|HJGker~d&<0j+M9pIdt3J2QwB0Cv`UGqTuOf0g%a4h!-$CU&mAsVb_PtIAu9s;BW!J}SD;uvrBGZyohB+|M@42)^Xm{=&I`hHChFk9<0dx04YMis+x zNtPv~i3_H6#<(K-&$oygLIDpbKA>btf{L&?7?ULtc^VTDG5~dNg!-Sn+qn6e-@srD z$0b{%0u`aRkm6hvjBBVx4Vk$2{q0VOIwwgSqoNE(WB%9}vXI5(sjFAtYU?rq5ODJ| z-^>^lC7Xi+Gsu#dIG$Pc=3PXa*uPcXlnPqgpJXF)5j{;Q%96pjWH2gN%oDQ20n$t< z%y#xbSykNL8dFxDIF3jr#>0cOF@FE%8weG|D=Gw#Ix8N*IY&>GqNvyyjM*L*?CPZ? daa8{o;ZG_Ii0wRLUq}D|002ovPDHLkV1ko~Iza#c literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/12_water_front.png b/files/opencs/raster/scene-view-parts/12_water_front.png new file mode 100644 index 0000000000000000000000000000000000000000..cb5c7a3a07545d8abe3255341d8acd3e14f5e206 GIT binary patch literal 593 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&3=E9tJY5_^ zG8*5`+@F8hLFD-U_j-NF-D*3WN(Gr89Y53{5Z!KMT;d|8T;KK7era;*M|Ok52imlr zdATYCZfEwKy5!)_JBCN5t~%lSYRe_zOTT-be}8xH`Q84bPv#u{-}6ZC!L|+tbEN~l z90kfucZgCk%Dp^zVp{OyoY=VK zzQ2w>{+3qa&+6qkH8`EG|I}rml=ieY%oZmu|Mg<{++)(ZHGp>?463FvrFd43$Az7%9y-wm$A20B0~-H2UY*aj>?TH+DZ)h z411UsgqJ>?H2cI_L2Kp$jt9l_j@64j|H+=ybmaI~$0sSk=x6YB^>bP0l+XkKh@l39 literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/13_pathgrid.png b/files/opencs/raster/scene-view-parts/13_pathgrid.png new file mode 100644 index 0000000000000000000000000000000000000000..531fd018f621cd52faa35708a9a045e0723ddd7e GIT binary patch literal 751 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&3=B*;o-U3d z8I5meczc8dN;K>*et#ol+T<=XRWTRmpc{8M_Xf`9IMq|O^qSI3$1Plkqqb+|tL*5O zb4ks*a7amhb(2T6XOIAMqH;*qg6lOb=jL8cO538AyYPvp)%{QQ-~XTgfA{zN>W5sK zs@{^$rOe!}+$-F0qqKWWs;cre+pgBDi@b{7I)P0r>iFm9sS|Dao;HXd@NsFEjh|(| z{qLU(2WI)Q{%l^T-xoUlY4M_yYo5e*Hg+7G!kEc+!X;-`;PK}lpKrU$$Gb*X>xBFU zJL|C6ZRck)6{KhR`W#v;^W?=E*>hjxUq~xmZ}=-$@vN2Ofc1l93k5y7%>6HSrKNs~ zx?D0l-(*@SJ5wU(2Q$I@lWs6i&@?>su))I2doFix>ebiGi90O?rJH-@He7nh=<(c~ z(OM#s&xB!XtZl3EN0o`{3+}Y22Sy|wIG1wh=49Qe`EfU^gSbW8cUiw$A8N9+WhrN% z`M)Jc&vToqN3E)gzg->tI_K`SyOlq)T#XwT13BNarMN9LG1fEW*>LyOc}A%g*`6&- z?4SP5zZai*t2{GxnlS4U#<_Y=Bm$-|u2nc5Wd8ehk8;@T05%)34QE7X`!?JI%S_dj|o)DX^4Ng!aZ@ie%Xw4 zzx(?{yJxa1+Bxl)X-axs>Hhbtb2)2I$^qvIle41cD^|*}R%G|xx4v^b*vhu*5TDzn zVBuX=T>JI&x<99%+kPSF;s3uv|Ftt1uVNyd%0~G!&-Ps3aj|&^FmW~}U&Kt-{hE{-7? zjc?C83N{!p956Um|LQ{LE=~z8H@n`3d!=vouAh9*^84m%7FYNCxBkD>aE%1`jnVB6 Wd+eKE9p``+F?hQAxvXQ>s2C1!D$f(hF0jHZM@`0 zF;^4|PMj60AD~~L6gukIfk+3PsUuqnp=g{HNxydF{12NP>je+?abUO9Wlw%5Q zJ$=6L>+I}ov6Jh+4ch8;dh+Dh2@&R8=&vBi4_mSqRqFMX|HYXz8=6!xk0%zLo0}|?e!(^OjU=6296hy<#II?CrEBjf2epX6RO7=RT{;mM1IB`5le3SBoP?mwQNfB7z{H&CF{>C{7;e@o!+nP|v~22p6;!F|oz zW;fXg=LG-u(mc(Jeo;yUAXIf1exJH`V_O1~6DK|+#w7sXB$1`zW>Swr3k3jG5YbM= zzm6;~@#IBsu~0cOH8u11pz&|*LZ?r*FR;P2z0D-9Cn2xqH2@F*>{9Rm5QP@Qdy-^+ zp?`~rjt(mFb?3n7=xD&KS4KW=)`lAKn&96T!;RP&!=Id<`0C3+W7kFZ`H@4P9{8w{ zMd6Mf5%0`UBW@7$yMD!2eDnqVe(ZnziLVKw7HYGSHTYHkqj>f>+Aa0{|9b5E&t2a$<;y z31mc-iHM1WRo@6e&9kM<{W&u;lWr=O>er%YDgobA0=}sPd{YVdrV{W?CE%M%z&DkE gZz=)beDDJQ0Ti%0*dIP%0RR9107*qoM6N<$f_?&>p#T5? literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/2_fog_very_distant.png b/files/opencs/raster/scene-view-parts/2_fog_very_distant.png new file mode 100644 index 0000000000000000000000000000000000000000..f75794e782de14eab91cd91896b047e7701a27e2 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt-oLT^vI) z8n4bcEqKI$$B9*G{^xJ^y}LX`XWvwbZsDKj&YHx)8GXEP$$=A<^KQRUber(*yj69F z;FFvCe}j1UQ@6FQnVP$>>!w&$NDg;w`3;sh)7cF%Z+ISv?%2A4^F{0Wi@T46Es&bW z7`l0N%kF76oqH5CH^!&rZsvTTn_?c_D6!6ghkv89x`IVx#2cQ757rZAtaVs@gUh6@ z_mZUE1^rFxjlY2i9c$*LZQwS(U97a=}=wsXFwe;(uNR>7kagM6D3`pCV0PYhVzw`qicpk4aZRwOwj{!G{ve80QZVq;c z_8)Ho&t1=YsHK7UTxc4&1eo55HGmqh7vT literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/4_water_distant.png b/files/opencs/raster/scene-view-parts/4_water_distant.png new file mode 100644 index 0000000000000000000000000000000000000000..929aa8adf51be9082a695b1bfc372cae5993d812 GIT binary patch literal 668 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&3=B+?o-U3d z8I5me*ydk$U~ss9vvC>ArE8&8t|coX7&;qUSzC5(++dKvY538f?>}GIHerJghRPc^ zDzG^uB`|0iWX+l+=E(Wc@W@iJwRf#@Yg~4z-<=RFvUmFCwbtCpJdbZx^jd%x45tDljvfF&bab@$ZhsSbB`e158AaMmGeN%Fk6S0mZvvQ^FBXov+fTODvu zaMk`Pt%}9T<%PY%Dy`G+^=9t4!*FKU<0=dTjdI=xPtL1$gr|9`(3-mjh@*|tY? z1-oy)(q^XKRV}9`iGQftIy)yV?4g&$(Ynx}RE;XGScYjg_MO?stlt literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/5_terrain_distant.png b/files/opencs/raster/scene-view-parts/5_terrain_distant.png new file mode 100644 index 0000000000000000000000000000000000000000..7c3bdac24367b09b1ac0afa25536ffb827ca6868 GIT binary patch literal 1152 zcmV-`1b_R9P)o#DTy)KJ^-L$^ zCPkoLDCnv>ea`!Q=Ty;EEi>a~mMh!9^Qr}$AOW;(yQB$W`tB0W@9;a+Hb%)L*-5w4%)88+39fmwZ~BAb zPX%KR=;qrI;6{Hi^o8?pJLwC9OSLFSms<6ucC)6yX|A3btdHV!JDDVhI*m@NQA6_~ z0O+%iF4^31i3M>Bfwq&0t!>6z-t2Gl_M@E6d2eSVWfBufX5Majv#Y?X&gpBRQ-?bB zW~WtmVetI-5MBN7qCvs5$Uke}{&Z*2Dy)wZ)<%gPJKR>I9?ivUY>oZHjW`YhWk;5p z-FCC~+@^~Py*I#i?G=3IlQq{7%Yo+My6rk^n~7ZD0Au>5W(wPF*Il<=Z@*C22LWaV zr>j@!fsDB$%Hw7M2xvDW9;|Kg%ApoP4zdV#S6bA{X938(pBowF1{W2QEI*|Jz%;ho zYOooPx$|I?*N%3O+#_M9$?T~|bs@lR2WBHPS7vIuP+@w;4#0uYX+|VFDfic7T8)Ti zJzNO;tfM;fG}{Zk_p_vhLduioxeg|U1FI;(kxrd>oU%4b2waohJI!1t_mV#SsP3;@ zxCZk1FWgj%t6yBj`636q*QkX6++UBa7P?8j7S@!9OTx(!1j1=HDo;A9`@0v8l1Ur| zt{FPVbZiTz_j2xz%xsOo@MdJ*FmGhuCf;mphBplFO=i{_PqN!PslOp;=3iU_dWIb} zqbrd~+6ko0Ik~{OnhR79oD?`m;6xa>J;43l3n!`nD$V>wGv1N#piIJtPAw-znc24Y zmU^=Y!`bu~YyfzPd!XB3f0}UWV zFgRgmMetLp!Ol2rketqP!QRRCqH0w`M*K-sDQ%2owXw*CV?f~yJq S!rYDk0000P0q|pihlbKu=oM-AkA<{ZdG@6vq{w zAaLvULEzS{ea__XzeoQM5Z`^rA1(*G8K06Cao5Mc;L6 zORjNQ*LMLvtm})u^TSv3`EuFT`0A2l&*uw``@6d}B!GzXHv4H?u(#8}(&va*wHN0r zhx8(HHM*Z(@_AYsr{1qRpXb0hZQs^*s?KmDbl(B3D{T!{B^hD^;}C;dtdg#bH9OvS zO0H2@?Bj$B3w_DzG9hk6bxAynZL{KKfe;P#JAg}hVc_2$;KI6zT}LZR5`Qohq>iu3 zVHM~L5V0fZ{BWt!i@E{Yh2=gc_KB?{;XQ|jdZO$)x>@?XIKCEB^aSm|)muC5yWBG01F8!QKWOa1IszDWYmjLfE(x@(k%&A6MTXS z4T-y_LZvP^x<7}1+P=5~2c~0vhv}d&T>^u^vXVrNvZE%M)~yp^(M6{s8DW9lCA14s zEBOT}HDhJE5@3H?JV>6PRpvL5OWUYyW1wTCa7L+d;xS>m7R@XmQ%1-vI6!T7y2hXa>sj6gO7?zRNYa7x`-DWjQiimD2D z!b{JF%2Mn(c=*r5Q(JR>cYWWn9!W+ByOUX2R2Is7h{3|x7`a}cIU_N{WMt0`m^R}( z(?Oa>_Li4+D7E|dvUv{ku4~{omaU9PqiOl_hK-OWeOtJd_*8^MB^s4d%eyfX)38a3 zaUdOW zKX{JvHhX)PX9$(9F_Md7jm`chyk>9ZEhLqicS=?{z9f_y8mnn)W?+A7H`skIQO_Qg zy=MStOt|7t)bcLXI?RHw#*5N4;k6NjSY!`s%$>OvJu#m~tK)wn8wI zYg^#Cvoh*`MOoWbPyylX2&PdkVfH7$5e~nLJhL>k)1)EjdN-Fa& zJ2)$w$!&;N%pLEY2wwTzuiUci^myFSvJ_uNXnUb~@srMZFgew=!X*MPyApIPOc0kN z=u2GwH{f?#>+NtC(A&0~?Fk5IrP*HB8a|m8_?f!q&~ldpo*w4{T9yM~osPOW4V^yy zzDvG-U*24f!R)K6mA<=E()~j|)E!a)?ed?0K8*q2eETf`KmGYn2hiXA{b4?@z}H{@ z<0Yb<86O@VUX6pt$Hxg~dBt(R{`!~0`@jGCczFNYFTWVz=YRb?`}A5?_>$Tef4TcX r;MVPfz^&T{fm^o^0=I5oJc0iLzX}rIvR4Tj00000NkvXXu0mjf>gV8t literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/7_terrain_back.png b/files/opencs/raster/scene-view-parts/7_terrain_back.png new file mode 100644 index 0000000000000000000000000000000000000000..e5d3e6174ac9577954f2b799037e82dc60423b35 GIT binary patch literal 1567 zcmV+)2H^RLP)cy(Sy?$%=jY- zFOqoAU9X>=Uz|VXJujK@I{-fKt~bukFMi2aUpf7Ygr7_LJ%D=vo;Ty?2;3L&841rx zni%NoHFcw@d#1NerKuZLiF?jBE0LLfi5yuKFn3x4~XU)9Z`@kQOvL!eb5OhYh> z!4QKXn86IFn-EGET(R{2PR1PJ+z(snuKiw6I?S~`Izf+mwurIVv-TEzeiW?a-QKD=69CHJY3 z^~r2BKAw)P;4UxuBms-2#j5>J|d|+z~Va_f96byjtLT(O^6ZWs;3axvRNBfCQn^N01tLTVUx21@>dPPT)4l zXa^w-+LJ0^zH9`D!FE(;ZgJ>k!2bS#5V_OanMfwrk?9G1oMbve+8~6|7tP=<&KK=M zQV7O62F^&rh?R!d2n{1pKyh%r;q6QYV0L_o2oO6!_ym&Kj8I3Sd+@jl6Eh+SmAl}{ z;S$^hWA>sEsDi>3jT;Q(R?h?W5wvz*)=ZAxg9 zqiqvz>V#m#C|dD6L9Ix1;0Db>_NYIT>yLBUw|Mp**M9oNeiv!e-O2m|mLI0q4M7u+54t}1ysgt~5!+;Kdqio-cr zw6Fyn8|}4)?Cktv{_v$Q|E;VU5OPwI2078n(ExC@Me`%Xq34;$_S!Ftm6e^3!(i?J zt*FWoVnDM<8Jq~$wsc+D36g4;ZpyW}5Vy7xCM0$8E8x3|(s@`Q+=bC7=6fvR?;?i8uk{#Ifu4B74C>Yd@C6KOfv==MHO`rBuO)NjljGg2rTh1Q7YRmi8PG? zv~nhv?WLLI9u!E4t;~X?1el2>3rv(m~}U&3=E9FJzX3_ zG8*6BJeV!)D02Mc{n;~p&9Y}L3v^oTBt+k&Mr>7=%%q*N5d`UWDJHrG$h9%q# zFPR*6;bS(Oe*3*YJM`ZB{6$*l+2g*j>pQ*?z2bRNLgR-g@7I&Z&F4xQ|2ysIvbAA* zbNX!FuL0Sv$*-p~Tv!tc*P_uZ)3e<*YxwZ zX!vENylLwGI7e16*HpN8|Ltr3dII}j?UlA$m6qn}zo5M2*MUl#x7&Old56wB|0k)` zS1@CF@}!q{^mC7~G8~wmuykLI-J81j^gPvudlx^<`~1&x;eZM;*3=XUOGK<6yY~*CYBft2gTmPz9>(De4x1eV ze+#9}v*!L&#U#xuyEe{n+0%6r58gccVAyzTV&kj4nQdwp65ecbWz09$dy{`=exlTt znE`843XHEEdv@<&a`jx>kYAEhHU4;ch%;PbZ72zs`yg!PeLhRqdzB(EtuT1H`njxg HN@xNAZN3wy literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/9_fog_back.png b/files/opencs/raster/scene-view-parts/9_fog_back.png new file mode 100644 index 0000000000000000000000000000000000000000..c98b7ef29c06f7e7bd463444deb355fdd7878e19 GIT binary patch literal 1426 zcmV;D1#S9?P)9uyQ?x-WSz^{3$VoE4ARNX`Rne=h>D1+(=FTlohz>0z+bH!fNR$cz_sfJ z;M#QqaP7JQxOUwDT)S=nu3a|(*RC6YYu63HwX47HfnRcPHnM|K@(k#~ky2Pl6E>I< zllBf*NwW#SZX5)y+n!)Vc6nr@bunkNHwek+k%Vx_czfch;a}$m{Ca=* zrb2+|6Wjz6N+u{UsU}FQCY(5s9N3_cNSGA+LIO}$>t0Tq#sE?0VA~?9KKu zx&tUgI58M(f#kFoEMvlwoW%MlY;576nVuGqy}6O@gVqJI5lC4;gn|UANGecL&9~Me zLI%7(+tT758wwhAP{AN;>WqxmsWMJ!!KxnuOolC4!Z?}WAZ&07o8~U7Wf3N420{>W zB7rPP)ij2>T)2)Y-eosd_p*d8oxgM2)dd?HLs(3V>V7FI4U6o#~I6Om~g z;BMRy%0xsclCY42#nWo~0+Q;|AV+bDEF{%^;#QQh46$$sYyx8w0_x@^GX*3XayN2S*iB7u3oIT!bT|kIG0dtsN`)S2%PPP9>x+5-?0Ng*%QhJ&=3v^K_=d1WpaK4$&D{X=tmPJHFM0l0SE g09?Cn0IprX0cADL*{*E3ApigX07*qoM6N<$f?i#kc>n+a literal 0 HcmV?d00001 diff --git a/files/opencs/raster/scene-view-parts/README b/files/opencs/raster/scene-view-parts/README new file mode 100644 index 000000000..3fb58ffde --- /dev/null +++ b/files/opencs/raster/scene-view-parts/README @@ -0,0 +1,10 @@ +This directory contains the 15 layers exported from the SVG in scalable/, +as well as a BASH+imagemagick script to composite them into the final 32 icons. + +If you edit the SVG (Inkscape is strongly recommended for editing it), export +the layers into raster overwriting these files and run the script to assemble +the final icons. + +Enjoy my icons! +-- +Sergey "Shnatsel" Davidoff \ No newline at end of file diff --git a/files/opencs/raster/scene-view-parts/composite_the_32_icons.sh b/files/opencs/raster/scene-view-parts/composite_the_32_icons.sh new file mode 100755 index 000000000..4febc3b96 --- /dev/null +++ b/files/opencs/raster/scene-view-parts/composite_the_32_icons.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Run this from the "parts" directory to composite the final 32 icons +# Also creates status (masked) variants of the icons while at it + +set -e + +mkdir -p composited +mkdir -p status +i=0 + +for terrain in '' '*_terrain_*'; do +for fog in '' '*_fog_*'; do +for water in '' '*_water_*'; do +for pathgrid in '' '*_pathgrid*'; do +for references in '' '*_bridge*'; do + files=$(echo $water $terrain $references $fog $pathgrid | tr ' ' '\n' | sort -n | tr '\n' ' ') + convert *sky* $files -layers flatten composited/$i.png + convert *sky* $files *mask* -layers flatten status/$i.png + i=$((i+1)) +done;done;done;done;done \ No newline at end of file diff --git a/files/opencs/raster/scene-view-parts/mask.png b/files/opencs/raster/scene-view-parts/mask.png new file mode 100644 index 0000000000000000000000000000000000000000..e075fe8f5beefb0405be91ff15fd36ccb1edb32d GIT binary patch literal 3419 zcmV-h4W#mkP)mtyASFVG zAhA5a0}?zSArZ+SBoyQbAtf;+gKT5GjFZ?R-lk`|dzPM_>AmlMt4^Jdhq|}=cK6K0 zAlecV)w-&>=bk#}TmIkw`@Ylam!I#jm)9>nJ1+nD+{&J(??0(-fK z@s!(h1@>|eqr`m#5OV(yp}Q;a5kP1!_b{4|KmqnN2IM1%fjxwfV(+iL+~fZ~jcOcw z?FDa-Vn6`nA$Rt%+yesY9xL8a0r?-jFF)!X0b`Wh`EB*T2lfvQA@$$fOx=S<)iy=t z9(!z!NNSP#BG@)+>;y{bJA2?BW|wU%t9v+C`a!%~6xk)(Zn0hc7KotAV@O;_R_BqG z%Xppv1b6F)FmW==18E0kqPqyMJ`~pPBp>}4Pc;l5~;luYrI_iq;0>L0B%L zGoxcuhuyf6eYx}kOq@oQCy@FQQo9LB8?jyV zsZ$ij4kA6*s~yI7?KPBN#4TK;5E`PuyF2q32*d2TQZyvBE7{C&p>Cr%QL9?0h<%~cu;@6x#THn!8C zu~zcq(Z z+RGJCfJR{kH|)t51U{|CI?dV|&N)&il&hnRP41^u9UhQONYfOTTGG_^;Isv`cC*gv z?FDMoc(>fPO z040NrBUDP>jzExYh5|5xLUI+S<7*6{Kmv%)6iB!AD-gx(2n46^2R?!=(|_ zj!?TX`yN_pilJtxRM}z?0c!*P^R4qd^vH`C6K}I}Mss;d+oQmqvZ}9u^bN0a1w>^~ ziV9tho|?ya7NyCRw5j3i&;2Hg3n%c6@bs_#1)Zc#F$yy4_vlM0Aq773nakOtgDFu2 zYYqSK+?Tkua1!4ao_^*p@x3%po&wm!FgtUUxEtggst}y0EDwG8%fHpbzsjuL+q_V0 zbL`|5UjEK9muDIb@@l*B72^1lTPzd2NTKw{NWb^Z)<%iqH@<&E{_5lRftDRU*0dU5 zAxS>9eVy{3Y_t5skBxEm+$gh`PO!YxVRdDNZnwkK^fc9>A=J}f_yV=HU*YJ<3nl2sTIEct(a0ZcyBEq$4j#Y33*T-KgdXQV9e^mT_4&rve~+6B z_oL1}a&5qcFA){~5GTSXe!R$;GZp^n8*Mgf$(?H$k!|T+w(}qWzy9W|{Pp9@6N*ap8K%s z&rw>T2NcXa8{`5yaa&5bLC9p|+3#CQ+<)RYmu3}z|94BAIem(W@+%Zef6k*1pUwIK zPg_87?fQG5y1eqe*8zCo#BmND*q>)br84}Y1SP#^q{loO=Nw9db_%Bi#O2MZwKgL~ z$-J;-?JeAI|Mb_+V0iM#5ddEM!P}YDjn4-&?{MP8$1rOfHLP{SR`b|{4^b`^349Nw zbk8bqb7`5`Yu5qcz3fafYhZUTy(v6GVhs zz0S<+9M=~X*f&1L$z#VD9vaH6FCr`~E;2JWhjYTQLkF4OH-R7=J9v=82lmr!cUj+T zGIxD}jg3vb`%fN0E5Y|eme%XsxV_Fstw|X8gn{Aa(h@UsR~es}CMuS>di^R27^+qf zfm)-%ORv6)C1T|8=V*2k-hbyJ`^HA`eM9NRi(jpu|1lPC-R9-jUMCU5@aQz1IAP|> zC5Ee2q9DXM$Mu^FynE>~)uDY93KecF-av_=H%-^b0DFz&v7$We!JliYP>l|{15J79jaHYV3i7NG0hpsh5QGwKD6=oC` zXttWfag0qYi??r6E>>}=#l;P}v86cn5H}YWNs^3y<2a_(tWlkOgwptF{PCYa!YQ<0 z;`Z_iHnCW1snzO)VG-vXF10k89khwqKVD(9TFm<2ew_64`BqZNc)aforC{Gki9#V_ zacPy*rle_#by;ZIB*EGQCyq{%BEdLb=`c~~6BR2sXGxN{r$Dz?#3)*=E}{%x`4lP~ zLqxDP!6r$zze|xcWp#Z6tzdGrgr`*=+#-EBdj`)3r62WM6A>6LM;NVGT3O4i+^g~P zO+`q(5zNpTK+$S~Iw#3|AuRtuCvZO^gY#X@YjD z*Lr9~gl=q!ZA$;F%=RE;b0}Gq)`Xr%tJCdQ8`vbF)kz48W1wKP66Mv13^Wge$1BpK zXw5+K7>t2!km?mY;Z8=C?Z!5PF3BrIcDyi9Ir^SQ3e=j?qqYE) zqHye4mJ6f6w^%MdMR?>aj(}F&-&`TuF!JD+SX+Lbz}z4(I+H>5jjpzz4(=FNSxdP+ zh2KfbK}e;}(QzTg@h1=zL0HHOH?0+=Vnh@g;!cfvs|`T2-NExro|%<`ViXbvKD9=h z&cqWmudm?Sn85e){&yE-q+j()-Z|zi?Q%HlwI0maEr(7O3=Xss|_b|BC{ z(2{`;t>4%6t8cTdh+;czwirN2Q=#6rgyWCl6(@1du~~0ZYh*RL>MdG~0=h|xwOjw4 zk7LVfYzGcLvblvQq}xr1lN4Q;B${}P`tlDb7Yu=?^Cm+EjvS=N5Pid&LC%+f7#M_8 zyPMLnnrQlyc*UtajjQ}fMiGXFN+|*b)r!a3Mw9M<(1TYPWOD_fT8>y_0hxY)^xW?%q5V=Wco_H?;}ORe*Q3yG z+}Lq!n4NK+J~oNgio~YeSlpn~P4c;Y?`QEL=)yFm`+k=0(kpD#*C<9lh0tWym#wqF zKD-QfNYCBG(r71$E)tDDiY_0`IxnTD6eGsRDrl{6P6z|T@>+w + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Sergey "Shnatsel" Davidoff <shnatsel@gmail.com> + + + + + Sergey "Shnatsel" Davidoff <shnatsel@gmail.com> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-fog.png b/files/opencs/scene-view-fog.png new file mode 100644 index 0000000000000000000000000000000000000000..0ba2e69cf731c2bea52363fdf76b62ff953dc8f9 GIT binary patch literal 962 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCwj^(N7l!{JxM1({$v_d#0*}aI zppNSx%;=;syMlp%>9(hfV@Srmw-Jt$9xL#?VSC#D`&8}yxU?V*qw|hg~Haa>lVQ|TtcVNHTX0Z#d-iI0(cE5VBe&yD)2bC?3Ngh(N zqUnlHclnjvJE+k9S+wdB$CB;g4q}aQD{Y@Ptm~6%6hD=b9WJgs|U&mT6k`--l1-j8NtIGjm?(Jek91 zxpjkDm>YBHuK1l>!adhITu5DQwQ=DG@yOIU5!susdOh0QI)QERbEjOl%=uB_PJSWY z*k<(2AtNNo3!WXfwUQ4b9JR3%liH7yC~AsK56%fSy@jm@71k-X}OpGudjZx z@!GXAL0gYU`oCQ5e^7_fhH>de6`_b{D^%H+zVnlmUYl69I5&HDn$9~u^D{z=wMO?y?OHYCm*@3B~=Ap{r$x5o0!M&=WWfW8#}q9rhiO7 z^Cf+3m%aZxJen2I77`Z>Bq1 zK6_|yq{FJ{e6r8#@dEV+C8zH_FXh~PMBq-y@m=%JC0^y+Jh@zKsg>-t<%XuI=7ld+ zJ66rVzWU0WqbFo%9>0HeI z=W1`(Q4%_SK%a9@w`9JL`Q8i4+j66qtAFg=z3Jm_kF%%N`<_;2yRN~bGS&a>-U{Ix zWfhEnZp@wF&M@!$lLtb(cRmpnlvMjDcj@PXo8BsI{(ry!aekoip<}l24HErERK(!v>gTe~DWM4fQk$Z} literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-pathgrid.png b/files/opencs/scene-view-pathgrid.png new file mode 100644 index 0000000000000000000000000000000000000000..6586b882e6c0473ce28aef884427a6559f35ea50 GIT binary patch literal 640 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sw*!1aT*KD=3|ao&A^KIwvhRtT zU-X_@H1W*r$!BKwpP1ttcEL>l(S#GTC!d`;1%zfyI5QV0*mH7e+@{w_Tb}iwo}at( zTGWQmkwCQmvvc%|sP!Or^oCCbyD#*gUYM}?Rp`nePVuipmi6;h@SR8*iYRGW<*ezM1qwVG6YPv2{O3}oTv(T?l_UnvA zCpJy|v&w&F<}st2GD^=r^+bwk@8CXN?P+#6Vq?g^DPgNj8>$xHd^BhK#j7u^GWvH# zANRgBXY#)TQyAKmB_5}EZM|8u@k{NUQ*rsbN_IOJNWI}dKDm%j!u{?(nf2yh^d8K$ zo7c$fGxN*4D~C>hJwIQB<=}B?foP$Z#|m3|fc{Y}ag8WRNi0dVN-jzTQVd20h9gcyqV(DCY@~pS7(8A5T-G@yGywpO@+MRO literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-references.png b/files/opencs/scene-view-references.png new file mode 100644 index 0000000000000000000000000000000000000000..aa3bc73b2117df07ad487cffccd165e25e7f7794 GIT binary patch literal 1785 zcmb7_X*3&%7RMuENr%4B77bI>GHQ(=mX3X=wUtU+VlSyBgpAmNR*`m;mbR9}QnW#Z zQifNdYK@(0GqpvjeTiKWHR*Yu-uw2>J^%Z^=brmJ_uNmH=wN3lcnW$7000PDTbVg= z9QITEyqxR`JV@afueYtG8Q|n+6w+R0aysBps~h1Qg7H&aCJK3Y&XlmVnXz-g)LJeR zBjI|k%Wz>J`dFrp){PdAIhLv4ZgX*lnv9mK2=bh5$7~9>Ynaaog2BY*!ruWi;C9Ib z1&ozcVp4{p!zBtu%4DRWq%yOC%CK$RCd{0 z3Wv)8`Ig$i%XLLFsTU|S&W<=8m)CVo?)dv7wvl3Nb~*$t@@EMx=h{hJJ>mE&_K!@N z+DtJY6X0-Fsx^edCplv;sp4Qll19n_S>>`4^Z-?ab4#RXVQ(EcK93K z$syu@$OT1-kE$c|23nWG=9$giWNagt-%4VE^6c!@dwn;pjh4q<@>cf*cEWe21w@~r z77pznC5qKFf(^DNSec-=P4}dy+s|~VcS4Z82Y-oVLkBf-1}%#*F!=`w>P1;sB2bmu zX0K2tb;GCSW=N*RZD<80mz0Vzovs;dqPChEHX`KoV>IWw=)Kqq3I4<^B?FAIo9}Jx zlQQCF#Kv%x6N*>ei#mGdHQ(asC#!~NdJ>~;4@zw0t`(E%Q&Zkp{A!w=%-^9~ecW3G z2|72MYZ%)oT^GkvJ{Kl?W8iEtw2i%D@|>LbWrJxEU2= zAx2m)y$NEESCH^*ozC8j%@4x@m+#LU^4eCcP~LwfI&Kvo!Iq^h9JPX2SxC2Lo3J=C zd$CO-Ki?Z4pm0gr#b$h5S%ix9tLrw6vDA4Re|KUdQ~>32!~NFm)>AE#Vy(}=;D333M4ADW{GYXX5W_OQ@p^N?S4I+z1A`e7$8 zq8b_4SQDKVUo~M=5XHsPF!c2*{?JqB4NSLaNwUh+g@BBeMF+Pb=dM$k7ms!#mvW*N zH4jUQHhR$V+eZ+gXQvp8`iHo~e7u3cTDO2sZ|R&NcD1{;fpyRUj4L?i`jX@Cec2fK z?;WLNzWu^-<*LcT{UufgIZh;@*}tW$rvT--`ju9+^SZ;LMp!5m2ZEaxv*Ui4;PdHQ z-+a=gy#Kxw{3MT{$UCBOpz~Kf#<9$K<4?;lpL=|E1g*zNS~}T#w@(efGxP&#z+prHCOi0pfrhAw zC(R$|@5caKicjBt%a1?5^lOk-ny{LY@igPvdRA3{@pQ^K7p{NplR>N`z?Fyb0@Q5Z zd)*}nqPaVnYhG!^sUJ)g45o-Q?{i%39vgpUhR>>S@cG7$$lN)k#Y z@qE!IGR_Q~lVGrn)Wu+MsytZ11_Cg#>)|DmTd;{~IZWrktIhL}V1qvP&Z!U9JpXFoQ}e!SRji^P+*{%>2j4WgAV2 zLIbMG$+xyvjjnm1n6L#^)%%UpevhwUghQ5FTu3}C#dlhJrBGY)K|FN^7cVUP<<|2{ zQr>Qs)(ap4mXs!IH{atcpU(QVbq}H3gKfnxKqy87r&{Nm^ z53onSY|jDC|J-m5b2}o^3+o4njEq!8hXjWEc!m0@VzB;s>%T)eLjY@YJ2R?@=iPq* DS?Wvm literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-0.png b/files/opencs/scene-view-status-0.png new file mode 100644 index 0000000000000000000000000000000000000000..b98230f01319d645f80470da546f7716b00fde04 GIT binary patch literal 2029 zcmVT-07~{bh14EC`~Ncf zkpS#b3`lwacE!NcI3@q2tDe06e~Uu@RO&+?`CdBbK;)v#%u|g2 z*KY3^uXgoQ1Hjy67(an3j3c#mq(&BW*sS`7xXh|qAisQvv41zX{i3vKSV)yJ|Z{f0R~(_3?*UIH`XWG5l+o42TWF=pIhs+CxgE2;h}hZi6Hm()FPTVQBKRH!ksD?HHCNeC6WnSVq(~Jy{zDCX4fj@jbh% zp$Z`u1tRGH_`&z)Kqsd6n67Eozex}r2ViCSIIn;A%VZ1R8Swm>v!k4QF=lb@C>!f8 zTbrABp38x$DTYd=bO2oX`WXFO2jO?Wxybw1J~Ob+_dm^5~cac4~&GrzRVn{PhgwbzP#{?$Cc zefuJRe*eYpv(rf>Y`belw=or-tO^!@CCGY4B*(z3;^$4zma&|wD@rTZyY`PY+3*UM1*Rs#{A+E zD{E^^jE!<^c9!8%sq1|aVeS5X=9iX;V`27V(@af_BM7t8(|r8kGc;Nr+dB=GR@SIg zcG3Y51U?VfH@Nzj>*R`M#wHKba_ju@>NU=teSz}uFe1Y0{d?S+Utpws07DzhE#JZS zeMUw`SYF$tQfs1>!m&)o%4NbZOlb##fE%~w7@qzVPNqm$zl)VAQ7lF*EH6Fr0stc;liazt$?}65#hlH-@e;OWpp`-?P)el(!1sNcjVcqTp2xH-nwf(H zwcBXlhJIm+7CwfQA;ld08G=w_X8g7G!qZ1Q;Ppgj8`zv$O&HOs!si{z-mLGQes(q4XGY*~?;0F;pJ4t5z zEVYg66tX6^p}VCxp+^~MU*;vv7}(t$+oYJ!AP7T+3|rfETra>FIzi4FqW<7dWXzDP zV`0#f%%m^|mJyTBsyXKxe1OA9@vU{aq@xN8~aV zS;s_my)L~PXiS925D;zcu-s!`Mh3r4&&l*p_DfQH{z@6A(mebm0iu+ze5DncB`xnr@S! zyn}5e6+4CE9~M*9p}6X9{Qv*}C3HntbYx+4WjbSWWnpw>05UK!G%YbPEiy7xGBP?a zH###nD=;%UFfjeHK4|~|03~!qSaf7zbY(hiZ)9m^c>ppnF*GePF)cDOR5CI;Ff%$a zG%GMOIxsNy$vaN~000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs00000 LNkvXXu0mjfiZ!`T literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-1.png b/files/opencs/scene-view-status-1.png new file mode 100644 index 0000000000000000000000000000000000000000..43b597c01e28d012d26e523cfae5397e0554d31e GIT binary patch literal 2787 zcmV<93LN!`P)yHC52XP+JdMmwGtpT;w62kC?Hkk2_ASredGa>eo8P{X!q*=q!OaaobK{J>DgZ1M-rN9`+~fdmdJ5^AokE(M z9DtIWoI>gb&i(%|`fmZaK|Ua>2VjX0ti&n#h^lHm{(p-?AIn)3sQ;D)njTrPrWz2* z3cp*OJP=e-c6tTjudnvH@M=kY)c|n%AoOfU<$93PI8qz~e*rNybnmTLy*rjmTYr{F zElZkK1wcM);}_3iX3k=3g=2woG>~Co_8fwTYG03Xb6`6tbkpx82BKQvTNMDVGG4en;{{89Y!6lvEYZ)@zlO|>}8%< zibA%Plo#epOkEqLI5UZ3S)?4z+BNNH)$Gh7!hCg#(g%mgxr$U*F6Mq5eH@2ec9kep zTUfyO9us31@M;TWQWia(IV`Ocfdo*}7;%Jr+amC&qrn4Y6~pM|^QX{ClTB#~ZTZD0 zB4CWmd&lqRw%ZS5+g_8Fp%GCWf8r*kRuRC%51$2zVo0Jx5sb0<<%`d7b#xn!BRp~7 zhd5Rciyn*`d)Bb`zAnz6-pa&ym8r=|YPBls`ub=u z6jru?_zTRv^i}fS7541jfl>;sG$@5u3f1sN;1o2}la0WMi#+peH;r5e;m?0Kz*|Qj zY+BRv_OW|Qk%vC>Q$!#z!mGcZC-i zbOh7v+%kmLIsy=XmC{WB8ikMKU)1x^cVFP*H=jzZA`)9lB9e#*62@N%5fQ>L`et(T z3~ss1!B@+;DU16bazPZvIK2GQw;3DVv1oy?T4eesj}g>LAR+7f2H3V~fa51WV4+r9 z3NaE=q_NhVCF8!QfrEc}t$}~dPtvO5`Id}ZciQIBM{^uHG|vk^o<%8zSAC9ZE!uu0 z0Hjt%V|d`6yU|)>f`DW1pJKy6KSTZfvGz4u#}?2!qLPlw_4*R)@b>rE|Aj9u(RN5! z*L3`bB2igF!upsn(*Nr0r<0{Jh1m}v}I#k zkv1c(z}WZ%=SIg71=|Pv=U6#@9SmzrVSL@+mnc7jE{&= zER{HOewa(6qpa;-!?w+v=_nKu?TZMbSFUhoc$hF0HV+Nbx3&jC*gQDMhW_=;FVvWs zn`ijaD6_M3%@k5fMM)wIQ7Q_AV-w??zB*6p;pb4mdxyVI&GXqbG=K^<cSY)48RzZ@Y%8~lqfD- zo58*B8#o*8jRx)0j2wE7q5gF!r8qZonbaL$B7M(S0I=3?|U(TS`_h>qEe|L%ErpwLg!1UZ4mR9t1wP9%$JG4qp zXT;;1&u$F~$QU1EOx(6S0U6_Cd>T5|D zGFvJFLT7s>61twfSg zN~CcWE$Faq0 zr8OzbqEf9T0vX?@QuRq?*MNeqd^$0tH0*#IuU8~i+JELeu);nkvSR%k?Q>jPBcb5f z7Bw%j%(a;X#%C*JQx0j@rcRqAc}6@~JmxeU-CCTsrD03F*!Hmi#B=yDuP3sPlG?bJ z5SNNq&$bHDHk~`4VS3_CT>CPvts_mV`ZSFg|eFPP|MubzJ~TmK?|tj4_Oj zM}Od+U#MbPcCx|KT9I!{)6q*K&tKAs<-GrgpH_E4HQMlNIHS~@vo)I&(* zywW7n^`nqd*S~*Nt>*}W*8gIVa&7W$X#}A?mu70FOtt1?wQncuv{SzNI%(UGNjX?7 zhRo<*p!wcnIRIs$-5hV9IvZ)qazQuW3tE{Dj(vC@5kWg`D7ExhVPkcy=lGcm>;<-O z?nP^bZvrk~nWb9usd?pClM-*&BX#RcA8iAVP#ZtOY-yTo+98v&>&ch8J(ByO1OsayHihlvHD>V;JR001R) zMObuXVRU6WV{&C-bY%cCFflYOF)=MNGE_1$IxsgnGdC+RGdeIZ{jxr30000bbVXQn zWMOn=I&E)cX=ZrSem8 zJ>ywCUced0aY$mvMu~;6qQpr=6ogU2rbx&M;u>*83P^|}LfjAsq#TeEE(k~tksu2g zIV_5ugg8RPiN~|pGJXkq%VKtK2RKZLfVKwlxm zZBU?(duU<$521eUp~Y>80nta^T8aKE(APAoZbJ<8YYzixDVi=eJ>c|dA)q?>_F`x@ zc@*90wZ28`{5Q&M8A7+jJhZ&-mEu}?na$bUT!BqFn4V9fg}dpoPAl1X?y^aXbd6Xy zo6z(cvhE;svWM_DXVBPFbUcR&G#+opXN&IbN_OE57(IZ-tx%5J{91rOPljcs**r6gBCsHe3(-TkhSp-kROgUNZ(JP&6!R;rFJGrzSVKyM zWhs;ZXKtCo^gGzO2{L;Qk)Jt>S6U%yE3#Umvl^!`%i6hFw2~&4V?#)Z4yodot&(DTdR^vC`N}eDA{zqiPkkUjv+gsT9|hj%QVtxSF7Gk zbZ~3%-Ybd+o~~mjTX}4R+?AR0NFhllB)NfXGo%dozRkbRJ;Z(YpGIr9&C1ZKQN%l% z5|Nd(6sD*3lUANxBX6T*Ef!t?o+o+vr^mVc@ffnU%(E|?LhI(uLoA>$lz>Mcy%@Qt zB~KZH?`wYZ((_zj*pFoyzIpN&SgIb09@6@rW@hRR+?w5DA46aS7=!rvo6}u75JA#f zWB15uZsZSBa(0I94cGA3UniJ7*9^=%4*NX(ZHGqoYb`uuPaWl#pWh9QSc_LlDy1Lb zd5^?1wtbpZ<|l2IKXha}M~@9NbKy>IEIF(!FH@^I?3kEfFqcCI9-Mhq@!(hM*hvEd zlGX~lN8V;}?E$o^aM#Y?$D91&wBc<8tdM&SDvum1K&TwS;uarFMnF@z=$ z`#kns4UAwY`!U(nWfqnn#jmGg%iU@>I{egOUVLD(y8+Ez|L(D-0bYD-X2ZEbY16&& z=sGqh%APn(^=Chf1q@8kR3d1FOgJCDZ&%{N%na9;mNxz8@w<6MCU(?I!NqKOqwn?X`dJUI5|tVT6oX-M&mKOzYbWJujkSE4+4%+5*YoJGocDr)XrGQNzv+1HvaV%# zp3CCW4bJ@Y1Jc=HM#k@;>Xi7~nX?={a+u+5+c3s(<=R!wPfas4yaOc_7v?VEx-LUQ zL(DBKvtFzqg&<*RMuvy+eIMQIB}98aZ*CTvt+3lXV0_Qx!}Ax|w&#l^l3D!HWvpb5 zY_`ty+$_0+_hF1-ZhoHJwoy{43;;tz<6OGB%-r=N*|g2B(Hyp=kU}5?2qDl?inxht z6Jyhx1JOnB-Vk(MmrA+7*uD3oEsIKW7hdrq(yg($G>z|tF;XZL*_E3h2m&wxrLu$6 zNydjWSXzaUG?AG_2zqTvxtXNB(Y3|l0L>rG^n2mAQ++En&>XI7SR$f;z^) zYCeyWg3;jtloU}wi>Cb|daYY}^`6r9RN&^CxkOpW7+lv!2th8B!f`x;+(FRn|9Bhtq z6~`ly-VOqWv*7{5nAYNN+EYf9qqQZsZpkfqpo>mH5QHy;z}6BI7%Z)*xuItk*QzY7 zS4bx;lD4J+8_{;*&_s%9Il5`xGl>6p<3{>P5_^vlU{i4$)mC7nX6WAMS-o)vTVKJ} zGPHDD^jmM{OiMG+JkmCA=K46wRR^UsB67PBkWMB@*cOFS6=(E8%Ja)uzKdd4eM$JL|<&(n*U{LN_l8BY!mDrIqNv2A|9< z0-&Ts>-MaXuq~7lIF5&3uZN;p8Ilu^Q!md_UHgb?p-d)aH&bj&ZP2&H1<|Mn0d+V0 zLuDYHU}R_jAq4fh!L}qzt3}rH6~JJmL}vDpO7Ep!nxmNih>BBTa3B$8D#F_EAB&KM z8rtotj{pDwC3HntbYx+4WjbSWWnpw>05UK!G%YbPEiy7xGBP?aH###nD=;%UFfjeH zK4|~|03~!qSaf7zbY(hiZ)9m^c>ppnF*GePF)cDOR5CI;Ff%$aG%GMOIxsNy$vaN~ z000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs00000NkvXXu0mjfI-bl~ literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-11.png b/files/opencs/scene-view-status-11.png new file mode 100644 index 0000000000000000000000000000000000000000..3028217ba9eee5a6ba778f58bbf1558cb9bc23aa GIT binary patch literal 3186 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 YWiD@WXPfRk8UO$Q07*qoM6N<$g2O2isQ>@~ literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-12.png b/files/opencs/scene-view-status-12.png new file mode 100644 index 0000000000000000000000000000000000000000..974519c5492035b8cb936602984064234b6cd5e2 GIT binary patch literal 3025 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 To9;Xs00000NkvXXu0mjfXm!QX literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-13.png b/files/opencs/scene-view-status-13.png new file mode 100644 index 0000000000000000000000000000000000000000..4c075704af5a59fc6a79634d564cbc6ea9aa9503 GIT binary patch literal 3279 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 XE^l&Yo9;Xs00000NkvXXu0mjfcD?@6 literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-15.png b/files/opencs/scene-view-status-15.png new file mode 100644 index 0000000000000000000000000000000000000000..3a2073628d3911d99cc2fd3836fd504bf3343fc6 GIT binary patch literal 3354 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 literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-16.png b/files/opencs/scene-view-status-16.png new file mode 100644 index 0000000000000000000000000000000000000000..d0fb5404766f61cf3c760960a2a0ce621ad4633c GIT binary patch literal 3078 zcmV+h4EghkP)UL_t(&-tCx6j3w7u$A9NhulwlN zO!s&)o-m&Aj7=On@gf!?iXaIhvLK2A!n?@=iIv5Y1q;L?3xwFP2n#kKEQEx3EfPVD zgTWF(u>-NK2v0KOneOpS&$D~__I=j#d@QPN-MY7X{D_!{kvLN6-cxm|>i_?~|Mx%V zlzQRs6X5~27ru6czkO-vfj!?oNbu99qxHYIe=OgPTB08Zz1=#P+=E+@-vu?Cqe1MqkiWC zy0bz0%GX&AVYL$i;h|%rz#|Gg0J<$p*1t@?_byf|JOj$pK*XeX86ib2eGKJyzyh&j5uH{*&Lf_D}8r!wR{Z01X+B{eTMk_jzf8d2D)|coHV+O;R zyl@mwhyqKu9n?~pHs=HwF8#g0sF(4-Y{lkrA>ImVC9shWV)H>d_$HN8_UOed;Aw;I0G4(JVHv?(JhGEepkUw9X!^pHA+BILQ{ zuU~qRTia*xJmELae*@1H)tkz(d1kqC=`qs8uRT;DI8h)nB`^b6zO<18CCr^s)wtOJ z6wr=5c6%d^F1IihktxqV`J;=Vo6iBzjEBEVmYoCO+SWO~@rS=o)cJ$C$UpP!5uW?3 zN(2o$;S z?SI*7>iPMjFM}Bt&)2YK?QkDAR~5FxJCLQqRPBo*^Ri z2Lmo$+2q>xHXBEeaQ5_RR+g9R=!*#3H*a!ja}(!;(;q*{@r`u^;q=Lq{LG1uF`6Xo z?T^^JwoR|MkInJ|Ycy$AFqn)e3WskEOYH#PvvZPJ%+Qp?bnXarfwqc5a-3*fQEnx( zEamo{yS)B`H)(a(IC|_cCh?GefBg-fd-l_;t*js-T)%mP3zsgly7mZ08!m2LB~4RS zS6A8E-k~=rO(XCuN7vTK^BjBp=u#uPLY5co4`X)sCj_2mr5hcP%we*!M&ST!3|4Ej zR_JP9k!KliU%1H1$)6_(yX3?7@WN%f-Ga+on=C*5NkoLLYu8v_Stp7*0IaSa6U)bO&Ve|FqZn;Nj;(d@ ztSK`+t-)%Eqi2%}mD`k{l!A@bHokA!?N4ykeBguwMOPMZxeF_SYm`=~s-V*}DIH%a z#^VH07SlP03XUKmsNLtULH?8{FKm=Agk6C`YmRO$WWvw|!Z_o#X)ujkf z4f~b_0|C8wqLxQP<15_=1?-QK%CpOC#A!j{gmxI9D)1%ngEdgvpQR`q_x8t(;uKM( zi)U2^K+zwL$@7A>Zd3!B%|*?lnSq5mU?EkAu+l9vu|G~pb4Ok{lDr^_0<@_B*T5A@ zm4r$HX(go`r8S}NHT=FL*dLAwT1P;^S~sjG)tR)L_-2x~HA9)NfjLQ4vuh{xu_k8} z=NPSs0w3E1Ujx_mt_&!PvhrKsYQzbiH6&@7ncI64?)1jA0+0&oyXxbP7UKslN1)w5vxzV z$i3_+zSa0v&tZ_mFf7!lZc0ZM>);Sc70wZ7MOn0!RW^%OYdr@ZU^Iy_#@72}trgvN z$og8BRumGfe}+^-vfLf6f<_I{yhc?6Ft7JHNj3CWIL9!~hyoAK+S)4L4?IA-yToIs z9_9GPGGX8WiqRxxw>Kos3Y76_9s4=PNkLw?gLOC;tf>0@ZE$nt{gH+#fMMv@Mz zNJ=&Hm*LjYaoUf5iR8|A=?(7D3O%C0qUxy2>>H^9yXg5MLXzbSCmABu65F#2R@rnM z%?Gs~U%3r{(YoH~&$8iRj3SOR@}elAc^$&zzeF+GWU}`Tlm3WK0000PbVXQnQ*UN;cVTj60C#tHE@^ISb7Ns}WiD@W UXPfRk8UO$Q07*qoM6N<$f}ODH_y7O^ literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-17.png b/files/opencs/scene-view-status-17.png new file mode 100644 index 0000000000000000000000000000000000000000..9d95cc85536e198ba0076bb3b793bbb4ddd59748 GIT binary patch literal 3265 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 literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-18.png b/files/opencs/scene-view-status-18.png new file mode 100644 index 0000000000000000000000000000000000000000..0a9013aed32788b93054a531b5560b4f3ebc2287 GIT binary patch literal 3201 zcmV-{41V*8P)tx&&-;c_xry0eZRFv zJ@YS-a2v-nU!3Kio?p9d&o{Rd{Ps|i-Pr+XZeNjqAptnb-q`^txx)jv<0+)?bP8$i z@BozD;S^H0@!9`xqaP@M+oS>c#RafK1GnOoyvL#1d;b3|3VkTCC{X{)0Z1BRufBy0 zw{VVp3Z?VMJMY=ZV)pcn2(y4T3gog_K)Z}@?avKi5TeI4hQ zehUDdg(wr;0{r`@eH*;mar|=!AcHO9?|%)AkfjO63#b{`HydCa4LA&=gyGqL&TlyT zJ(xd=YR)6wRitwjk|B~t=*0(d79Y4(L3W{*9j8ok`bA{pA}VO14?K#q@Bk>ich*pVh?n)nFHYl3l6 zjK5!sK-3=bncyeS@ z9-h1RHRA|T{~F=iGU1>@5{0-6hw^h~{0#F>_5* zGHDjbtYO$cOWOGvuF)8y$+U2Dt537;<2QVa{&2ljJG+@G*3xaSv$b}eerFS{9bDJJ zQ4n5SqjUZhyvZe+2Tstw@ES>PoxpQw8I5Tf!p<_Arye(S4jY#bw~c|84vuhQ;! zm}~|WeW={bz6qcF7fe2iUJYTAN<~Lk1sh?k>6&_gC}lq>B0<~>oxLXD+I;z@|RiP_~r7R*_k((Tlg#D zBxP>0j&gDv)Czw68$aN$AGr&(j3ogygWeyLBu|!SJnv;{%|9Q@{E3HWdF=5SE}XrO zo2wz~YimSN$iAf|CMG8_tD6bk_Lo>(cmbvQWL9XjBJMtNlh$V3QSgB44X z3158qRo?x|@0Xkw$sGpCNg^VME&hr{M6fphTWj_?aQF(}`)&`m+~sD~H&n>{2Ne?uzW1w{OYt)KeZOPxg7|T!>PNIQ%oh=N)|6-U_~ z@qYZbt(P3nk%I>Tc;(Hv@~j(|x6l2Q`|f)X)9!_2nMElGJQvq!P-=`aQW0M@Ac}KF zYpfOeiAHROV_b|xWhYM41QDUr?Q-tIGM86YSeTpT$e}|_O-`2C7ZFyjUE|#HGS&)* z?mocM!aRa-=)eK)+5Zvx!-&mxpXJLdY;CnMNt$6CO`K$Ohkdfl;u(jDhL7i(G0Kbw zKpDh#@9=eoHi}GAtY~bOH^3x`xv_eaSKoM(dTWNc#d{fsJ^u66*LdvVk1;bfg@|zF z+Evb+JJ0mYJ{;|E_TnYtIA(f!nu{xIY;^}{rSM(D+{_GVnqrpbCMww#k~E{;3t4Xu z@m!4M>q)|%cE;IroXswuP)o9gyZfy3r zx!GrCqE_xE_Nqc*>-nBRE40eN>tb0E$1#I`hlOJgVO*C%u%D#+4myswv3i~~$u-jH zblE?-gtZpL((8w46R1_=bi%vaiDim&$gHj3>rW<&kVZAfNN-l0I>=Ior z;CvUB1J@|6P=%o5ILaMgDF%ZGQ3j`ZKgyp)L`c(wG)eOJ+YHGv);G7%3KnM?I9iP- zszPZ!%HFo>M-vg4YUcagt!`M(u@&kJq7*C8sQDG(3av*KNYfM%A&yg&f~i)Gn(yIE z9xo}Drnwu6wQO}efG|B#160MnWru-)-g%;=M}^~4tr`kw_oKqI^J;`~mam-xA60vuv~n^uriYc^^%R3V@>18<3_MGp$+)Xw-|UziI_`=ztxiLWHSSUWxV~ zCQdDBW{J{_TFpm01>h36La98UJb<{MQi{@=z;i2pp9k3K4e;x;pkSsIludO+?JB+z z4zzfR@8hCQw3iF*X6DZ$VFNBt!Ff11=l!4abB4ln?qK& z2Go6*z%wOnlo|!8P@`>5W$QMkfpUe&4oX#4j;`YnxDHkX&ojAbmCm=2+ZCvQ2e?^( z3jg40{5ak<8&4jc4>22H6Y44vp$6b!4Xw_MlW|En$-7qAjel zDq5}e7$VQ6q0^{E;%udfQgFy)6lzx<;m7-DiF~%ABe8npD z`+z@sXc4UyNt$ux+7@Ay5XHSBlTvj4Jl(psMB}c{5v~4^t?mZ(z@_FJRGD=deIr$1 zc6z>u5G5(SVS-4p#CFXNtE@VX=KaRo7j6LH==@XVcr{!cM-hezX_n>C+$O=&r^))u z3^z|R?DT2YyphFLJ}ixCAk8v5{g^bfxUPe@4SaiXrgn?=!;H*YvN&I2H|jof(+!kT zWSQW(n$?XiTkSzk8m-aI!_?{r$$A&*wofw%2gNeqDKw$@ANn0}tJeqo_y7O^C3Hnt zbYx+4WjbSWWnpw>05UK!G%YbPEiy7xGBP?aH###nD=;%UFfjeHK4|~|03~!qSaf7z zbY(hiZ)9m^c>ppnF*GePF)cDOR5CI;Ff%$aG%GMOIxsNy$vaN~000?uMObuGZ)S9N nVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs00000NkvXXu0mjfcXt_6 literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-19.png b/files/opencs/scene-view-status-19.png new file mode 100644 index 0000000000000000000000000000000000000000..d57fab4465943c7121dca49c833fbc7d9dfbb120 GIT binary patch literal 3327 zcmV!f z&y2^DaU98T~*2?okfNPY%G29Jm{&G2;kAl*7_WJ52 zbZMO6>n~GvVYuW1?j7fPj)mt~0F(0j3UM5p;UVV(N6fZt zZ0pYVOhf22m+{vZ@LM&)j*m5d0B7tF?#NU=FKphTv3QZjwF^Xk18;mkr3a28u`6;v(BxRMQWStScZXPX~st@Xf@~*5uxed zqW)ap#l=Lf(P%avMha$iM6pA57j;~@`Nk1gw#N_pVe2I;XW4NBp^PhZ) z?PiT?$?eMzm5SLH;bR}W43cU{?n4ox$mEN!e3qMwhp;T+*IxV!EF;cLPv=IV$^7g? z1RXoqP=%0)0uj__e*ISmTMm`^w-oU3i51SD3%GhE%%dSF{O0cx1iz3!W7+?X=l$^j z9lC&j>+MDU^2rB4%YYL=(`x(KXZ_^Ri9hy>vTFk zyC)~9RI8{@Jol{Bw||3)@mEo*Nt_79a))D&uk!Y}gwau(pFeG*R2rc(-~2Rho&S~F za^&Qxf8ptmf1!_z>3{s`cQ8Kx_zrNwH~;lT&VT#4+urlk$$#dfPk$Z}h$G>vUkNBy z91a~z_`%!bsJMV(DAqSMwe3%#o;m#$snw1#G5I}y@t1!e%ZgDb-Z&dEF=2D^sR~!# z-AfqSXsxs4)OnKT$(kPz`g!l4{x#P=_nSGVMN)-9Qj&-Wl4SpqAR;75`tOyROdq(x z*S^}ob_`B`)CN&Rk;Ru@{R5U3kD^XJb}grnZT|LI-l#2yy%Rniec?FhM*Op342?|U2O+a_GYnNKxVA%*BwSxwR9VKQ^| zCYP_RvbIqt2qG$_B2k=RPVTDY(k3E=QOtJ3=ZBXU8LoIV8XJ_$Rb0nQ=aq%4H*TW*D0OIUKi4)VPM_Rwssj(`yWn^MOntK`BasXN@hRPmOV-@PH z4xPxxvE7unA~=>qv(+L90-`Wtd3Ci1PC#o#p;%_|<_ck$%5M+^w3;<46OU2cbp&hI z&mzulv{htfZJj8Lh@yyEt&ZaqNRoskj%YM}wCS>ESDBGY0n<=<9(AQt_lioY?g-3ZBD8-6s)J>FXwD7!pMxi6pe6v{&*R3#~M!VIdL|hCv3PlPbPav|1fRnHZ(R zC}$KAA&NqxFigLn#7G=-YjX>&U}B_*p;eyTB3(N(hvyfioAtek2n?0db?#Q(@0&yK zqe-gmMbAm4R4bJ3fy`A%gdm7e3Wmxao?~NFkM}tvRYOSQ!%g)thd_ zcV0*j`^vneA5_40vqRc`Llnk@Q3wd0>tqE@w9m0kjfh~GMpgu2WwXuPa*cvxQTFVdHr&anGU#lxKO}jF z$c_j4I!DVea4liG*+Cly#bO1mjI{U3Ta2`+4l`b_6`sY}cZvj?R?z*pLbS>7vCp!x z_9nJ@1KZT84XWD@_V3I|-uZQ}EBbO^Aj{?Ml!}uCKa44Q4kC(bbtI!uk48$RI}yw4 zn*cQ1K89iD4W8DDa?xdMq)fqcamG#(h)WnHcV8va!{~?}Rkl0gYBC?Vt^t!o<(eTKYG%R+xrH zq4Eu_E+e{jcGu=2U=B1<4AO=^q;V|N+hN*bICf8Qw8|2D2DT_(6p0+BmkkLvea- z^amY|ZBj0}2tuXga%;1J-w81)M<`eo8aKa%YesmEh0&9dY+qn--@@Ff`8gN_KZs~{ zLbOs83l64fWQO-CP8Nap8%Op}ptT~5Vs0#N;deqhK_l~|WR*X4xArC}KJZI)R^MQ& zzCppY@EkMsex^+M>Q8~WQ}acHP8iW>hlqe{TUb_~*So8&KHmSR@!tGOCb#KURHL5yygUX;wGtY;Ctv(rAq?9l$H>BW_%wzI~CF-=b1< zuq~sT%KQ(gBOmwCoEB#Q001R)MObuXVRU6WV{&C-bY%cCFflYOF)=MNGE_1$Ixsgn zGdC+RGdeIZ{jxr30000bbVXQnWMOn=I&E)cX=Zrw}shXiJY6GH09fBw=bV1cdszkeBTd_f60TN=#0*Mt1Bo;_rF%(!-f({U= z2vD1dwn1%5?8J5wJ8^734{yBl$KpQU=jSAy)LgK{k*@AL=bn4+_y5lS8_xICiQl`z zEo>*AALgYOmv7nn=B*TdqbUiuHvrA8+vHRL7%JM{0F-QV0Nb8Idb?9dv&{i0+2#~d zw{Y$MyU~vY;1=0{qz7P&4cv@V@*!PyBNE1 zL7CZ`2>;P)-w8A#O$yZ_IAgVZmG!~Ki74SPq;G(N{VN~zDUfPYeMQYhHlnQ`S z-o&q8AXq(*sTGz1%F;lN&e{b84>hn0Wf#G;Q0Tt*r3*ye0ADHqY|F;BZv4zN1h;h+ zXL$yvUB`DFtkL~sMh=jz>`vzSts2ewvotTAA#j@HMkgrlIg*kM7}tMBqKL+NjkVow+g~FLbD#~BHc(pk?y7rfmGn`%J4b)`4iv0a4p(2p)NUWz zAW)qA>3y`%RdD?)9RKcV466rZYxsHe(eog&4@q<=LJ*kz`o$Mmm_LAJ3C}$DGb|(Q zz8TLAe3R*^eR!^&_)vuqi2@PS&FVr$yT*~~t4yzafm&z0ZxzpZ+kKM$f;i)rt#jsKCq4V zJofB5$NkTq?bm|D>%H)u9c<=02!DC)IZmH?xNo}WJ;c%dbsjnXOGF?HgjfEw&Ks{g z95^(``s65<%9AZvT)wzMef=A#hn~JBohg@{ch+Jmm=S{F?9y=x)(T^#bDUXt0w*Yb zG9&4>6VDHG>3iQ!C?yhm7$hc%h#*n-E)gO^6vg*kvBmiQIbMCGiJdX{@*_5gA_y%0 z@Y^49W&TdovAZuN6e=FF+4)QXQHt^MzZlKWaAx5N+%W&Cgx>)0i~A-(-8kn-Mpew| zt@Cz{nLPfu&B>E3&QCcgrSO~|;kXX~Tij^#eGhBbB=cXT-|< z>`t*Ko*$<3lOH4kMiTWvM4KrSkH^pZK}=3hv#_|xk%M=jmEy0bPIJ%EWAS<5vlRAb zEeL|xDN4KxJ#F`R-+uw!9RoP9cP{{MzHid)8ub&o#NQN_fQ!eL`0aodW8?BE-+NtiJ=W9XD{M; z9z#Pz%+4>f)@Y-ZB4e5Cs8k4oAf+Afea?I^$>8{x$Ye_d%}ZF>GNn?;h1nU(M-C$* z%wE1sd2obWE_T^NLsc$bS!Q;jK`C#ud!&qQ8EB1G)l2A>LmAP5izjmGKN9haT9?8->2>PWb(tHpi+uU zFd|7l*yBFk!+kg9NCiL?MX?^0!ZtM$36^Q#dhyO&TkWv8)+V2^$l4|wv{6bDkP4Lm zkWELoQ~)gHA1AZ-7!fvYZzI|&M4Jp9dV!Utx3JAQY*WXY-Z)pt=A)7H&KuqF)Vxru z<6syjN-305Xssv}vW!$pzw? zWHT0^XmvblYfU^qL>V^u>KAFdAwd}Rd6~rbT$d}Q=!HBlpymZhUv(pCE}Ox1eLO!z z=c;5!?xnHx4#k{_ZRn&FC-f*IN)q8At=j08ma$Drg)D+FP|Q+WZQ{5-#=t@H)&R|g ze~>i;av2MQp398u0-LKtDFHY*QAKNoAB4b2h}P)hescM}gw0tR z>t|^@Z3YS%Y%8wVDHQ(!q1HInh2cIa0000bbVXQnWMOn=I%9HWVRU5xGB7bTEio}I zGBQ*$GCD9fIx{ybFf%$ZF#WPVX#fBKC3HntbYx+4WjbwdWNBu305UK!G%YbPEiy7x zGBP?aGdeLeD=;%UFfjJXJ5K-r02y>eSaefwW^{L9a%BK_cXuvnZfkR6VQ^(GZ*pgw S?mQX*0000)zYl6OxFD7>R0?y1%c!syhF3{^x(r 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 literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-22.png b/files/opencs/scene-view-status-22.png new file mode 100644 index 0000000000000000000000000000000000000000..afb0c7dd5855d79befd867a96748b69c0150e07c GIT binary patch literal 3389 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 To9;Xs00000NkvXXu0mjfUutnA literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-23.png b/files/opencs/scene-view-status-23.png new file mode 100644 index 0000000000000000000000000000000000000000..bee128d24d554f51c6b8024e9bae0a574d040a8f GIT binary patch literal 3464 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 literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-25.png b/files/opencs/scene-view-status-25.png new file mode 100644 index 0000000000000000000000000000000000000000..151278eff6d41440c7543a54ac6bdbfc6cd6bc5b GIT binary patch literal 3355 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 Ef}@6hbpQYW literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-28.png b/files/opencs/scene-view-status-28.png new file mode 100644 index 0000000000000000000000000000000000000000..5008026a158aa85d88540122261ef728b29efb1f GIT binary patch literal 3388 zcmV-C4a4$@P)f3$A9P4sp$^y z-8c2?cDs{yx7)Vjq2om?M6f~vBCKp(6@B8Yg-}=W) zIKty=zrD^sd~5s2J#9AIzrhdP)F~;k(SZm6X3v6=@7tZHA}HP1Wx}~2n2`a zK1`r|$f>BvcxQ3e0#wAVkI87j&Yc_d_qGXxfH>3~TU$aO3WSI- z%61t1>@_-(B3|v(`L3%^7}9Bh5vAvXs6f@l>ySXB72QtQ+;h&8ml-#<-or#O?ange zQJ=|pgjO1*6-p@{2lB}TTNd2A`94KHA&mnzRyqV)HwFn+tY#HQ=(guLCNtw}4=cMw zKx(6_9H>TwLLrJ7rIfB60HXs;7}9Pj##zC^-Zs5XLa)`k4^`K%yo*+vR;*cWcV|^Z zz}kqP{^UiTIsXHUDHfs(^B&dpr@o}r)B)z%t!L3dA+-}Ti)wGAitf~sPCF&H5QI@x zMpYG#>0@8|(j|~eOA|v8tTp`Iw_f4)jdO&d@b#C!Nf@}=hH9-X4OcEcMv+HN4OIwU z6o_CDH8WUAV{rYe5+s$aN~t#9D{8Rwq9&cTIagsMf-4!QRJ zF8zaFNB!RKenYa{QCN@GV1j@k(3tuYXpPp2qO=s&lNFAvu(Vrk);Eq3Ckfs;_V@QV z*x$!_M;sbNgwlDw`p>WO!5{oigK3ef!XQ#-R}f!+i$_H8zWPo(BTk*Y&a2-U62$>8 zelY@3SR3+BfB#3^yzvw!i6fG@N~}_gNp8@hz=RRT2(1LX2;;ou+O-b|w8kUEp<%fj z69)RecKPb}zW>mEF)M%-rVp<>e!=k4OC4T&ZNy*wXd! z?c03iD_wr=%WeMcyD#&fZ+^a!ZKfV8?z0rBqtXys%@ZDU5YX$U^d|+m6{1kjhqO@= zMNwm*7e8~t&qJoVUfrKL@zmpIxo}1Cw|{e&XPl$<+#8h{_a^>!6? z6Y}20|K{<>KZDubA7GtBD@7|!iQ)*Qb>mEhAwlZQOojXDJu0KUI0|p@wj?wm__Bs1 zSX&|@^alejUfJT>jT;>Z5Qx^{#8{R7NoGR6d&N$J?@4{*+t#4&3t%OpvHAQcxHhZ?&VnxuG-T6%_1 z2~rO5aMcB`52RI$bY>41}{ASSyp>JM1GuD(xE6s)YQaP`JE`-3rBDdNzuzPgIF7IR{KsVQwDLTMcb!;G7^@6k$Qj%}>r znQ@`{X695yc#kiK#N89K4n-K7)vG z_1ZO-dmE%_2Y{88P2Rt`&DGljx~+(l8_PstfL2wPS4v@Ov^5TBt>|@Ax~-Tydqb{W zzs>Q@b(F5=kZI(lrgQb2!aEE3fIQwnDMgw@IOppIRWKg)Irj8{#A8G_CesCW$#sXBgH zR{Fg|oMUHiAFW_>wN0Q^LvEP{a2oLDqD)yoTZllflVG&s?)EOOp7ATgD@R7-9A{QB zy=M><<4MjWE73}`)J|qqNQ9!WCqCXsCtz)&;IW4_2bSwtk$Q-7dEF4M|BJ{cmgK^Hz!H{+mqqQO{ zAbsR{Pyr%BURa9Kp_C$u3`r8z4iq(%EJ|zQAYh#3&9rLEl5tiNx7I+xYBy<0_N=eY zM)7G=tvc~s^O)zr0;KBl*-0WyU>RivfmTGT=OJjJ6m;4NT5HCW9PcY*i?ZT?_r4OK z6p_)07eW(|7gc8N>`l14Kc*FjB#~)gqtt99uij6l)6A@foB5P96C#HoH8(kiK|m4; zMf3=I=_y1h9E$!}P|BlJgwl(f_V-#Z5ubhmPsF&8rgDiktUUb+yZ2rvGS`Vr-9Xhe z=<|c6G_8Gly{bYiw(tcWJOEP8domxBtbY#G)MM)3icULWeWgPj&2}P2lZ+rR%^Iy0 z-FCvpYL`};5N~{rLJ~^rAB=+e5oi7$H3z0+j?9y$;l}I%=RL#Bk{*ANC`##e6VfCi z%S-yh45bvKan5L*Gk>(ZOB_EQ6NQG|{SjGSGMW?&#}yA$5YgKF1;#hOht>)c=ow@b z4I-LxtbSb;0kbefu?QRHJatYOOf2#G^8~F;oOliflg4mW3vHzlMd6wrFeUF!VVm=5 z=F%i4&r6EZq0>#0jprHMdy7tLhyvZbu1-6@n&Q8i$>un~Jl0u+(A^U?}T1iM68&nf@neCz|Fo$cth>(|-;iN=# zi)8&gy7L%H2MtL#Ry$~|@m`1{!@a#B2mQ%HgiWCFb(r3}atDAwYmCu{vJnyliYzO! z&Q+#`9g-8jiW_Y)*?Wgce?%vZW+is6H!N_#I!Aw0U{y-AdY+(j8l`o;J5>FR#s%Za zUIU}~qtl96TWO<}!g(P&w0rHm#}(Cp*KWnEuT&Xzu6mohyE|b2U|fMlYjo!eSaefwW^{L9a%BK_cXuvnZfkR6VQ^(GZ*pgw S?mQX*0000F!+^ksjU%&#v4k1{uXoT3%QVSt52o_#+o59^y zt1Y{W#xC40yN0aH8nQAg=X`TS+=#;>;zhofuCm>r^omG5MZ}F8=bZ1H@0@#Xr25@| z9tekc{Px$U`KNDh9-4fkBt1;~0XR$@MsuhE0N^ln7)ND?4&X3#7$t`f;4pRkKZQOQ zfJ3DaUjTqZ)M1nyK7|fbhf!ZZ4yZ$vZ5(y@01mZ`I$uBz9F`6Nj8^+0mIu)3|4ISp zpxg%ulux-;_n&XfPwAci4VceOp`S{4?s@Z|5;rPKK3&ZIyv!o4Rj>op)H#&WIe<@< zAP>A#Bhuvo?-@rA@9(2z#JXXw4`)exEg!E=AyEg}UP3mn;}{1-Nbh}snqB}vrvsD; z9$@@uyM3rr9k|Z{3~xV6&gkq*qJSZTauv!ibneO7-#C!K}{0iaR1%jy)pfvY8q`!@FL()4J zsRRb!bsmVlH)NTEy;L$7qG?fO0hu(%)S~h*6DWD6a;_MKP{l3Lxq}_)L8L z`#7YeqS#)(NSdYuQzvojGbHT|Y<~|)VPBPghCyqIo%fe8T04k!79daT;^=qVY~5R-wX=!qIQXvS=u`uJz!4%s zcd$kK<2R{!3V*Uz#Ji|Iu1l=~MwA|Lq5@SEuLA;&R@7^5`7BK{qGZ6z(iM#7Q>{(V z>$d3kx@e_QTA`HUJP`H!*d%7-?oHyTPv|?$9I4@GT^c0hzS^%iLcKbYW3q32fiSmA z1f(!JkAW&hC={aDPbsAf0ARF(ab2nvMQ;$Zx3fvJ7SOCTKf$UyH$FluO~uztRO|ay zM8H~)58i)~C!T%_W8yI{!ziMn{uDz>4FNEk-Fn{}D5LOV>eiEu{}du-5SR-~I+`D+{=;@H?-46W2)#8}hj}G2FOzhB)%d8mbU7 zQ6Pdr)V{$=N`nQ3WEmfQ@GiSMn+Njs!0IXYTL<%j$AG{5v#X$G=z?Kt)9d^JN%AlN zx0fI0n}7OM!rGsVdH$(qr+EH_j2lIy$>F7!cR+Tr*5zOR@ekSCc?1*q9)Yh&)0E4X z|C=PWfN*Sfmh-1i@&4tH=||Ch=%Gs9jOWpKmH2(&jqiQ`f$PP70W9Plm^XLT@X9MS z-h8vm-~9D1N-5&OA2EpX_QMQ2#w^P~!!JMgJX&jPn)2RmmYL z=Ty?g_3-{cbokFd=WD-^f6 ztNi=Fy~d9(zEA=*C1Rz3+>j_vxb)G-oIQDxQzss}zwyQOIKA@vuSWnvz6cHt%p}_f zk>!-h3d1Fn;`u&^N6w$)>J7!;{p~tWUU-<9+7GEz|AJ?pdOk1bMGCUKd<_tOaPh|g zJbL~dCypO0*dQpC^A{y3DXz(tfF{c_lm?wCG9@4xSwRqMZC(^5kHWsU_jy158_LdU zxN!P30PnnaDfhZ@xpM78&Yyn_v%TBKrYW)2JoESy)ThB3YXtBDC6VuH9JT_R0!Jr>9sr zdzR+JMCpAIVP$odYfDRHnQ->x3FeQ^AP8qqoZ!^)V|4owJ9}N0Zm+PryNC10!l^&j z2(IgMZ>P=5`ZhazJ$%o__Y8N}*SWrQlc||`g0RNTTencaM5B%fv^pK$dix!$@@bxW zneHIr3v+*!SY5nj{- zgmgMPOis;F32O+7>FIfH-dW+~@p+U|EZ$gVVqyxvHjQHp)2Cj zBwYIFD$NtWfFIPcom;rU1oe8#;_?y`PdJ>lDQzUwd@9Y!?8uRy6A&$7dR}dl8X!34)L`OUY787=(0tJ>odVCYIIpdsM3v zdG{H$iDFAQ^*DFeR!NcsfH;onbz3xMpQbu}0eAZ65q}QtR=KyaiA^llT3W3(zF#5B zGP2at=?>5);MjDX$wmd^s4|a+C0k3;2S`!JhtW_9jvlE}34K=Aw@7VDnx>>#o|-mE zur?u+jDBJfcN(X9iokaXD>bsrk|c2fAY$0*_IeSb3{LG~ls|=tU~Pg;l3ah5B5BIj z&MsQP>|_;3t1`JohISSXF9&6q_4^YMXx0LZR;+JslNLR`6p3k*JUKI`iD^E8py>4@ z`h&QnPFaOSh+~UV(5#1qzK1jMWI4|kdk4ufcH1pLIMN6KRoXXf@uWZ@0{Y-Uekmig z$`vBQ*7hFO7Dgp0NpWqOPa$Yr<4~)H7@ha=LkbOn7-LA&jP1Q1-9e0~eB+c9&HzQL z)5F@7$wKESWn|RGV%(G=8OZ|mIi30s8s{%#b=eFqAbfs&Uv5XnH;QZoMI7#dpms=S6ftkmwM=xwBdeE zm2qdA(U9aQi><`La1}4Pjzi!IEjh|f=LPBuFOsQ{R!>kWLn#lX6ycfQVmM&~xDq0>jd%t_h#4aXH=M$yOvP>xb6%`yg= zPi6W!1ce`jW6fKw8W8w~LBB<(*9V~6AK*A9D4C8zsqtr;rO0$g4z!J{Ai06gW>j7clF^CdcodHTIy1j^QFCwTk zO7B(c4d&*2JlC+j+hq_Xbo()#UY-Za@ut%M$NoRZl6|IWv;Wh=Jj{cz(G20l@g z5GN@*oF$lfmiESb)Ix*j=yH=W{Lqj`LdpaO_H%$yt}{-jev~q>4#E5{;Z)|zWqfEj zD16^guLdXujhe&uZkK4p=+VRX^0|W0s0D28bQnYlPU8Xg z(dbdD_)HzCqLm`eB(EqVN1A1%abEkY6`$!Nc|_Ax@LbLMcAMS3UQQaV(Y14gmD8l1 zW!ig}=?!``s(vX~q4*z4sbWFXyu|zf001R)MObuXVRU6WV{&C-bY%cCFflYOF)=MN zGE_1$IxsgnGdC+RGdeIZ{jxr30000bbVXQnWMOn=I&E)cX=ZrOo17YgvB9VpAK98#_p9v;q2|HVPCrkN_zHD z6hVWw4w}@7oi;)oL~i7V9!+c6qC`>_NlAQ&*c{_!h|cWr$4ZVKONVxxN-fa2~Mc}D;^V(x7KV()PP z_dJEvy-p#;Jq|$ZJx(FHi(~(P82vy1?vfAKoddAR2e#vs{Ry|yyZ`?!3jI{hA|U@; z7U*hr+dJ8S$Zqr9&g6lpg}B*mguk=eJHpGR`yB(o_(bly?cMSJBH?aFyUWAf5tptgT$d5+LP$h+hQPLr`7c+XRU8 zz_%j+e9y=CdcSiWOS^G{*5VYcW|gqr!rOC%%-}Jy10!j_u(3pa_8sc)UqrX+Jlr9H)&LtQOd#d92|kx^di-(Kfq}&Phmxys zOD?VI6w4Q;b|?zDPI|r8sIhcwmg@2%p5u`56nl1+QPS;~^C2H@UrsxZqfnvh_ zB>H$B#rzIYsJ*s^4g(hEt`W4?$YmS``-?bAr2<(%?8b;=DHYa%$1gT`K(atoA7K8T z&9n{k|Fnu}-8o6kOkQGsW{R8#g99Z>g*=|;Bg!Q*1umTXMWQGN%0ZNaD7Ai;@hsg^6c|}j^{+lmvLVmx=c7TK3RsJ5R~IV!OPm~hnTvn_ z3NsfjcS+W&|29GUqiJ8ye~nz>4n*$V?HU80ETOXT@TJTG z5A1rGbAS6S2Amr_@wgxor}op|`!sL8`O8}XpBjIer$6!44e38VN1wic^W}%x$aS!M z@4L_Q<{Q7XWt_)OeT$Dh{bj6$NLya{PC%iY;n)eof1cZeM0p%XSX@?AS6@J${MB1_ zZKBQI`<7xVxCRr2oc*isFq~iD)T243-#tJW`Y5Fkk%X7hb&y_n>-oSR{Wb6Z)@M>m zSsO| zQ@_2#F3&vUbNY0HD-$h5grM~zt@ab~XBz~8Cx@{%zP1L_>0=BNQ`4-4H~G}3^0=Pi z-~RP^-hOkPdhWq5?uofty}|0&ex1Sc{k-+VLtMP{E@KA{a&UBiZ{d^c4y`(UL54>4FgL%#4O9)55<-VcZyPqOyS z&!M6kXWl*wz|R~#!sy7pgbfyvn7@ccY;sLJ2`G#)hyrBm&fjJ581yf^V*96fsfdL9T@X8Gv&V<^YPbz*JCT7kLw1+LD{ zV+D?n4l^>m7iAqpS*%sm>QyGDt}{13&&co)#}6N*QZC2N4QL%=t)*J4F)=yC_1RhW z?B2z(u`&88l~nuIT4rzDU}9O}A zj&is>eT^Up=6k3wQ?~k2^i7 zm_Gd?2S)ZHB3zxGA@lIBk^R}<0KnNb1}5UYsaJXQ#IbnXFy!K;%k+&tP9|GI*Wbs> zRw$Jsu1-%;Ir#wATBfgGr_wh_E>{Ggzki5pbBj#htWnDQj0{%rJtqkkvBJ}}kXs(+ z^$S1d%=!P|-!HyH6ltO;qF%j?clhxXq<3JPW^I`u2+*NsZeaoc#IJOPzRW|cG{U?NSu(L%Xd_U$e) zP|o8zlKN36bfy+4f979O0d9Zk!$dklI@JW(u;vp5BIq#0ItF7RBvHdb7m;)gIn9c!-qZoGkvPzE%jMy#34;_UlBWbMe)pSB3ol;37N|A9Knyq#!kPbtd zt&mK97YGcLvZ*0$T7s}$Z3BPTM&;^hx}9{T+5I0E^w061`h*aIWWZaNk}43Z*iK z5AA1oPlas81BAv}z|u;cAdC>lCqMKNn(YW3nXV|4#-1%}rEQ{6&!2Z^k z2m;Mgpu4Op0=aC4b~_{pBUEmP?BFBR7S2=5x%iGsHyND}5<9Q$66wxSNaW7-SLr=Q z6!rd#LB@9}6|z_?HiS|_s3T@>tk7zQw1ax0 zNt-O!V|AN_-BP0ED~zUL%!3;zw%rd#kt!zSJU001R)MObuXVRU6WV{&C-bY%cC zFflYOF)=MNGE_1$IxsgnGdC+RGdeIZ{jxr30000bbVXQnWMOn=I&E)cX=Zr)h*$_?J29AG2``vg;4Bb3D=UOh76@epOOUcaVu2JaL=+SjK}t-( zV1y&vE#ep_9(t;_yQ-%e-+ZTYKNk1C``#;e+YYF_;+9J9-E+?S#{c&}-#O}cza0q& z`26OV7x{;8Y#o?5H1ORZ5I*g<819#vcbr>ZF@4!Lo_ zLVOAi9H0)Pnplsu)gLmLSY1H`?YT%%B2w=1tr&#U+r~fMioc(g| zCQv@&Ro!{LF+XK={x{BiVhH_I!i&h8yHVVvEcs|L<8^t4bZ$Tvp%zY{lr9|jNC|S+ zH#H$$?(#e1=+XNfluTGRs`b$->E0~H>kCNSLw44XtxGt@0TJx2w@{0x0MIr|8yMwU%JvGq}wq((WeNu#MP+`ITdYwHZWmJV#Rtyib&V0MGUC+&j-1M~M43 zh_=><1|8Bk!aZ~Xf9Vv#{NZuZ``h$3-lq4#n`BXs@X&D@M;^ws8s3CBMJ_^|+``_z zNoW+t)mS6!tiQ|r;yu)7S{Uu)=z95+k9R^l=EK>{bGq$q_O@=)@9d(rgX=mt3Zko9 zbS}S&H@iyX=vmrVUMKBs6L=0yqcKfG)LCQqM{5|Z9YjE>B0(C3sT8WJdOgo$*x#Yw z*(T409HHK9v9NrYdb2fUoV6Lb&9GSpP!x9g4EtTSZ*9=o-NJPod{=X5VFtY~5F$c9 z+NS&NOEf%%Ki??xU9yks(x`zEr6+=@K$YaRPoU9?X2Y%Ktj&qjh>f-PFrH7nG0ULe zVL0fcl}2fWQi_v6JRFjx37gm7Cy9rIzQfX714rx1AfbrWm~n(=eWJ!>Y<%fqVV4L< zX>^eTRf$k2L@_QYrAr4u@{o&fKgomV{)5!^Xzy;(Y6P@utq-AU{mMINrK$Ov*?M!# zA_7_F@z#$X=b>{iV@xs?WtjA+-+JLI z+}JpYafRRc^4E#d0b$_blr*YJ_*vkor!IjMTB;a|kY$E%e&cy=Zk)n(h2MJa>$r|B zZ79}eso~1SV_9aV)L9v%|mHD0wkaP^S|V;e&z^hsm99EX3+a8Y5Ij~#PePzZ2Z|& zcvY9LM0gF6UqQgDK+yHm;py^~eJ}@$@%|;uJ?&9LK>p1$RFGmBlHngYd8a z{2b?B|H71+Tx-}t8&`QVR!zrwUg!7xYx5)nc2@>6m|ggh@k!$zN@C)RoK zdp$hg;qfneAc`z=`Nwbl3D-C7M?HG(g9?^QOaIM-5BxmGaom;;FwS8hX6<<9kU{rzrA@IuuF^^&lYdJUaaZ2WW;q z=sRB#{PwT?`o3uAuotr%SY?EL9Qk{SK{&W1-`Nt~R z=CQ}V#)vmYmj3Y7(}gld%%RFDRWXz((2hf^8PXXh#F^l^dNQOF#pzWB=8}({$R{CF zj2H7`C+VLuK&OTb42OOO-+Q1M&lp>e00W!(V<#;~c zpaJk*LzLzyEyd=f)RYTZmKCHZMHa@<9^-!ce^f7pl2iBH2f(XuyjeuuxV(4qC!9R_ z0A^>eOJ*%vDQaPe=a)1nC1*=vt&|uV3C~A!6h`M_NpeG;rMSk0JT2Q3$g&g>q0{Yh z@yZ(4Ha0l4xWK97$7#*ZR?!y`Hg4SD;@TQ{E*$^NQC1HvAqdBh9_8M{_s}24?6&)? zUE5%9uZeF4pD*zR$wkEI|+y04kYdl!emnsZCPy95wS0t`a2elBYc+ z8vu}|3Ab)<^4bsIpw^scarqd-sK5vJA7jI8#xZh>&KMb}!=k%}r{d&!MFSa!Pnjelm7S zq`1J%(;j|v6&vq^Y}rNtoH$KFiW#(xqNkv*@quOM7VnG8ndk> z!mt6r+}twnU*F>D%`VNF$Kj<}Jl8=hg(^2)Q=+YMKx;*-8Pcrz+}iDNZT%)I%Zn&o z^dY0jOIgmv?-aSsAnp?TODLrX0}pHSa)U}3^gA4S@Epc<83cz(yO+>O%&ps($FEPqA4OM1&8M9xUS~he*tQWnl{V`A z1I5>gZC(n6h_JoWCd<;o_$*@>C1k3OX`MsRxW=JT4>68IW-WW&VP#-Je+FxFcG?5_ zQG%#qA5F^)fTGhIkY$$nQs;)D;-EmC}k+E@g0Xj6jwJnS(-A4QvBKiD41^s6=loB;bHQ6 zMM{D&m4`B215=PH>9Y}d7$>72B{*8)&7T9OhEmX|2WYJs3}f=VFg8hx8p!j!5TF#E z(MT@1#vx9M%-q@?a(iz;&36erQ^7_lshm`d@6l!A=w>EUQgw*zgVaRl=sFI8D)0J%fMWqvUuD5~-L=v|;YS=h@kO4bQCOnQ{YFqo7aT z%t^JikH!lYVtNaos)IW~%H}yy?h`D29#!!%<#$D+9owW3)M zSekEA3j_S6&yz?%n&o#!!9)!(IY(Ioqc%q-i>9iL@egdC(~B~~mB;bCkY+O=3_PMZ zrPC`~-Tok^KZu!p>dhHeR(w3yu(Q`Eic|W-gx;X21Lb(smVb`H^?yTag>m#4GKvZj zRXc{Nx^FYpL@^B;COoxP=ngad#Yb>z%UH>2cZZeXsuWraJ(9#$d%&o8x09@TA7w5K zeBwAINi8~DCRloe?&cdbLWAe%>aZ^3e!0MZ)ss!s0Fzi}8cxI55@im->XSINl_|)K z?lXMf(5we21v3qYoxMKsgwd0a?-gqWVWttVz1u5}qBCcxxij=`{(!(_guaV2rjfD- zo4&U&`#HaI1|do^`f-Z(<_M4c0@|%thWnmdGD%k6=4Hf5Z^}^P6!$u3jxVFNBF!x8 zH};6)v|2mLes!@Hu2MhpCF0w!u-Dz87Py4IK~+&7ol=UFnEjkDBE)G%ZU3?p83G zd>S>Mg}FLfDQqry`);poo@0}u!K>GN7UznLT3ejvZtry2YYz(0XpL^1AgtYo?OmnY zew#rwV5aU@autgI0Z*)$IVV(nIsgCwC3HntbYx+4WjbSWWnpw>05UK!G%YbPEiy7x zGBP?aH###nD=;%UFfjeHK4|~|03~!qSaf7zbY(hiZ)9m^c>ppnF*GePF)cDOR5CI; zFf%$aG%GMOIxsNy$vaN~000?uMObuGZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs P00000NkvXXu0mjf2hFzO literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-31.png b/files/opencs/scene-view-status-31.png new file mode 100644 index 0000000000000000000000000000000000000000..3f8be3ac17fd5ed55683a52356924b4d2415920e GIT binary patch literal 3553 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 bV_|S*E^l&Yo9;Xs00000NkvXXu0mjfBKWxG literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-4.png b/files/opencs/scene-view-status-4.png new file mode 100644 index 0000000000000000000000000000000000000000..f29445f5ab90cc4909ba75453a1cbd581ff54ec3 GIT binary patch literal 2708 zcmV;F3TyR=P)Ss4VJi4so!wxz4M*>o$s7`s@1c<4}^O-p8f6! zzk6}zo;}~Zm&SL7lH~pdpt*O8ydwY%mEPX~l-%b4?t2R9`<+6X`y7Ch`b})c^GwC0pSPmvZjs>SI}y3VkS)1OZW_i6jYDsf1bZ z?ixVQZWBi#%U9+JgEpRHFg8@e(7J1o07^D1j!-W4fM+*0ML=F4n)TUv(jX)W!d|2Y zQTJH67L{WMFUsDfQCql^r3)M!%sa5|gpN7SZf89Mo?Z3B4XiHjhahID->LL8g?=Edi^ws;uJ z629}?3s^>yo1V>$Ba=(h4-p1-S3?y-Dhfm}yhpl&+5twLEy7%a*}~c zrGF47zK;YE?ffCS;M^5}=f5|~X0C(qmp?tnyYGB)%e*lB0w)jF_|lhui3lXI@bVuw zc;i){!^bbPF*S~*3b;j!h50pV8(;4apmpUso|7e$wx8mR4&4=i*>j)Hj|7oSVIG?N zC;Pwg0V0B=lKqtw5#hp_lZXgjsmWKrc9~aRZgAnO!4pregH(xQi$DDK2W+e#>klBR zHwgV+1?i5D-W7mXUjHko{xwhcs>(QhOXpq-l!epHw6}mXx$JCrz22o#UmKuJOz>Wxn!M zkw3rs9PhpRc=y?Tt+IwIw6Cpo&l__K3_g4WrS&)5A>!!tp=?^({=;2$J5~Y26aE2<> zr{|F{hC~RL)(Mx_!O$qnKwBo-wlQ1>v*2M3l+dQt2S9{~P^;IOzBJ3i;v(atBOE?( zfWbwOVn@#0>RQ6q)>DXQW4tih@>5%3?HvxvTBS|2RXT zJk03CL$v({e|!5KPM>;=;lV*fgv(d2aDIA*q2XN^+F)vKo-hm<8X975afNEVg;om3 zG8r8nCXVCV7jsG}O8fWW?HZ>(Gf%V82FZXVso;kx>-9X*845=P)%Ni>ngpE{h$7CO zpJH(D=WyIIapNN_w?es`Ff%tx<-{Y12y+VyR0hZJyb=IILlewjSz+#4opQlu_gDqn zGSEt)RA$>JmKMWx89aWJs9vWzzeuy`cY!Dcjdp@U5yYAN7933!XB-a0kXEzC`0+K}wW#00d-3jH1;F5M^SNj-Z?oM1(kwh@%Jr zBu$VcVRgNVRxmMK#L%i6+>%!roq*q-E&}ezFr~u}W{RN|lBOsWO+Td_Bp6yToac@> zju8>UFh(gDEPHs4jZrz#rC1!tK(^7T)@y(;G~fZMo4q?Fp5!RxZu>&c&>#&{Be9^A z!Z9_jYtZ%+!Z>BE5qAv)Fin#%j9A-fWgb-7>!Ud8ZhUKv7D<{iS}AmE{tjg}_lV^` z(N>W-D}6h)c@U=rjVuOiQ{%Zt4j{~_6r;4pF$`LM&^0KIB3gcgQy2jS!{to9MDi*; zKiS+~k-X%%D*&~Nvyh}{4JFS+D@DB(lcYizr-V6}G)*%vAjr$~>+5Zn zsx1nRg=?E#+9)MmkP6k?=4{%!Z5u#yVUcL920)U)M(*W)W4Z7&&i>P+*tEhZ}?${~n%V#KgCbprwtvI1a8Oa4h?lcCHAYkL%G-XT)%6B`5Mc})rC<%vxb}BkGsbf)40@88^#!)}Ej|%|V7*FXY7R*@ z?b0j*(@?a-B&&&{1i!k~V9Urt?C60Bv{poM!sV+~{2(F-8@VSlKC7%wKzoxE_dG?g z^d{B%8U@$Fb4*m%>(c9y-tPB-xY?pHw?Mqn>SFE$saA?46>M8`eJxeSaefwW^{L9a%BK_cXuvnZfkR6VQ^(GZ*pgw?mQX* O0000%el-s zb7safo}2CX8oNpCCQWeLL^LK;M1e+Ck;q$GsS*e&>KiXSARa*op+4{c5~5OtkSY*; zD5wpAl$56A($t;=UovBR#vaeup6j`veO(_9d!Ie$%pB8Fu)z{bI@)Wkz4qSU|NH*m zWvv+GE4Liar{DG)UP-va^Q zIxem=_?~SEe(N^g#v)$3PUw3$`;U>EI6;1FHd`0AHfgS0qIq+U$ZJyAf0WXJ(+|i8 zti7KRV`$Visczh%Ro_Ny3&*jr6nIM;)UUmRTbZVG@C>!#Apdi>r5a4l=Ma%p**w$Jh{>1 z0cn9~Hx_ST{D9aGc0An=v%bnZR8Aek%IEoc+pX)D(MnUyX(~hIohTv@MJ^v*_(h)h zfj+*vt+;|Ra;>Yw6RaVmPUHVSR7FB~E8-7JPG1S1MWQ1?0)+PZL& zT#8yACD2qy8+J-uq49_3!@+ zsKGT)HmlP2?OHcAZ}ZYiCEk3q#b5q;6{Qq`_xpH$QhsCr#BZXB_}r(TL2FGE$DF@- znMV%Ha%gro)xJjS)B;*3RMKg`JKkj-e*DM0@}*x-oHEn4!H8gtLDHWQN%~?i-8IIr zu(-r`zH^6{UoP`2FAnifZ@kI}??0CT+(n^85I+c+yL^SChYs<`!2^SZPy7A!(kPwy zN*7?_oNgwd5wiorB$P3!;9?}bzXRgb@ng(iSN!!~t#SI~qfC_Era1IGjE;`7w6a09(MBsp&aoLE8zYLMegIJvWqh_Q3nhvhcelwu|2qsFe2&Jo z8$@Upm%qWG*=dwgTwPoyo_Yb9c^NE)Q$B!^m@C(Q!qcZuChrYH<}S}Oa`0Jl`7%-S zCQiOWxg2wCX_3n5ClC>qmY1oFOi(D402m#eDS8x$=si7Gm!P8Nkk2!e#7l~MuE3o(_` zz`Kbux}P_OYP$spqr=5S=rk%RwNq8A6wEy~G>Jf95@HNEoQ=X5V)AO4AN5p z_a3iE8lwM4wv?7ul!k1yQZ(8Taja6yn4W7==eV{;jNsT7evnw^?skW@YMWxtA@AB5 zZL;La4rRIu?G6U|fZAPn4WLk9&(O+0Megt>o!FvQ5BiK)IPzuI3uC}{Suegs?(kU* zF72S3Z55(zMjwBTt@U?t?OV9EPBg8$pY1)FldSUV&a0or0!pbp0F*UEJNLxiwLqz8 zQ*L}zd&nw11Ab_9V_$HJ(Q7d)tmapptDgy z?pgYFt>KJ6i?&=!r98?SWi#in)rt|I(T-@egkoeEA59X{P3`5~=N zK(n3rfwEkRlb@lz`hB!kNh#A4GNosS*4@{2^|}YZz&{6d=R~MpUck*y5*b6S-eGlp zoA$ma+0X!`f{h+JlAm~r#`<|m1sm7W*(ReKLJ~_z zpGZGF3MEAmvF}s6w1DXZxC5TaJ2sUe8>L{RWYOBT(@J%3%egk?p*(^xT*|Y#-Nf@l ztl^Usone}Henj4mDC8WhU6koM$ev8xLvXZP;>VY-CYrKb{Cb<#wN)fe1=0@N^#+!u zu`CDBcwvlJ-T9x0Vr;QdtpjlK=p(*VG^D7zVa?xgL=6Mtl8yI&j?rsNc zHFly<-m%crpP@^dkFVbaz|tDq?mxKAxek`4@Vt;Hj+5^=CGyjsCvGj$*}g=l-l9}+ zcS3AWZWtJa!nQ|qX_>g**+Z#DJEGB!20cc(XfrvILn}pW1lR2sHa3PhNUS(i%rQPX zgi?w)7F05UK!G%YbPEiy7xGBP?aH###nD=;%UFfjeHK4|~|03~!q zSaf7zbY(hiZ)9m^c>ppnF*GePF)cDOR5CI;Ff%$aG%GMOIxsNy$vaN~000?uMObuG rZ)S9NVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs00000NkvXXu0mjfwsf({ literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-6.png b/files/opencs/scene-view-status-6.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f9a8a99f34a646fd586e622f6fe1ef4a0f3b45 GIT binary patch literal 2877 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 bV_|S*E^l&Yo9;Xs00000NkvXXu0mjfjqPFn literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-status-7.png b/files/opencs/scene-view-status-7.png new file mode 100644 index 0000000000000000000000000000000000000000..ce4e20e005db25bb5db28aa4b78e2e58328b208e GIT binary patch literal 3144 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 literal 0 HcmV?d00001 diff --git a/files/opencs/scene-view-water.png b/files/opencs/scene-view-water.png new file mode 100644 index 0000000000000000000000000000000000000000..0289b3c2cef68a5d43f770ff674ea4d4ee785675 GIT binary patch literal 1066 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBgK_U_24v6XF`S?q~4wPkytX`_6b0 zwB&eK!WXIv^ydQZIPTye?;>?)`76Mprled^8txq*#mol8&nPJiM*_a#t)TjiKnv6?rm2Co6ZI|p9AUwTHyk8 z&%}F9CC7snzjrD<;aqauzwUHo%Q>&gQ(_kZ8*|^RN!3}4Cg7KXf+*&UC z*PeC<>a9HsR2kI@3Uu$B8!1>ejS7voit`w03*85)5S5w<9Kp{1nc4iksc;D zwKTCsqMJ8uEG{T2EH3^au(EM_|NKTrh84~eRNM+S+(~^t{Y_}AYy}S4T*z{*^S%Fg#+eKak0b(rlyv8n_UcvHS+5tUU7v35uq8C~QOJD`)9ouIpUD|)7HsD`Cf2d2 z>zdh$n+9pz%GWfq*>^5pEWBvT>fOt?ua{2?tQJ{TuB#>@I@NcM2{7Sq*q0gW>N;1n zKv^wfK~=0nnpKd)p|6U@%TIGOOl4xQ+dtuhGz+sXFosl1Tq8?+%fw`5jxwe6^m4U(EO?H_m8glbfGSe#2H5gkNnm{ysJ8A6?)F276 tAviy+q&%@Gm7%=6TrV>(yEr+qAXP8FD1G)j8!4b722WQ%mvv4FO#qs>=IQ_d literal 0 HcmV?d00001 From c1e6b8608b619b9231adf2faf881b4da66fda45e Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 23 Nov 2014 16:17:58 +0100 Subject: [PATCH 06/98] Always create a skeleton if there's an "ArrowBone" node (Fixes #2117) --- apps/openmw/mwrender/weaponanimation.cpp | 1 + components/nifogre/skeleton.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index a409e8807..c59a93feb 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -55,6 +55,7 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor) return; std::string model = ammo->getClass().getModel(*ammo); + assert(weapon->mSkelBase && "Need a skeleton to attach the arrow to"); mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, "ArrowBone", weapon->mSkelBase->getParentSceneNode(), model); configureAddedObject(mAmmunition, *ammo, MWWorld::InventoryStore::Slot_Ammunition); } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 4f6921d89..a3fade5b2 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -111,7 +111,7 @@ bool NIFSkeletonLoader::needSkeleton(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: * There are no bones used for skinning, there are no keyframe controllers, there - * are no nodes named "AttachLight", and the tree consists of NiNode, + * are no nodes named "AttachLight" or "ArrowBone", and the tree consists of NiNode, * NiTriShape, and RootCollisionNode types only. */ if(node->boneTrafo) @@ -126,7 +126,7 @@ bool NIFSkeletonLoader::needSkeleton(const Nif::Node *node) } while(!(ctrl=ctrl->next).empty()); } - if (node->name == "AttachLight") + if (node->name == "AttachLight" || node->name == "ArrowBone") return true; if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) From 5a16420231c42d2a15feead1173aea899c0c4e76 Mon Sep 17 00:00:00 2001 From: Sergey Shnatsel Davidoff Date: Sun, 23 Nov 2014 19:47:53 +0300 Subject: [PATCH 07/98] supply the correct icon (without the red line) for the default rendering state --- files/opencs/scene-view-status-31.png | Bin 3553 -> 3441 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/files/opencs/scene-view-status-31.png b/files/opencs/scene-view-status-31.png index 3f8be3ac17fd5ed55683a52356924b4d2415920e..16d80af04eaf6b0fa840ce5b24ff381e60101368 100644 GIT binary patch delta 3255 zcmV;o3`q0g8}S;DOMi+p2;>Zdd)zOaj(@B$@b$qgX|3k{)k!33BU_8e#&sOyfC$;$_fb=)!12)I$HDbKle$Yf ze;RtF3IPVApT>>R@gyR>`8G;{*bMC$i~_$FqIEto%`EBe0#+2s`bX$PXVBF{*!Epy z_YR~zY!czjoJG%^{p@=mkjiuxen7l?7ssy<&YmHdJbwxgFunA)P;N+e`!bcl;JeNP z_w*d_igso#$?gK_)^&VG;X0sP4Pi)k=LSfE8as^gYT&pJ-2Z-;iLZYbhm1@VTT7S8 zvW#Hz7;b%vNof&v&HV_Dy_Y39PQv52S-C@g*X+w=3#0_A7}T* zJ0$H*0@o0@3galEB%>P(Mr#KVP)Y%UMqwN?B!6Gwy`JaM>uk~4+r(PIB2?>5CTEUN ztvC09%d!-krDSPJP^s>-RIk%w^X@Wx+Z(v9gYRl)CdY78&T3V#TSVyg*J*w9IyF!5 zCu$?nUtx?;tAG)uN0g{Q701K@%^Iz!*W7X}%PdjSXL<2sjOSCWjnVDw(d%~5N~5$w zDSw6M14_SS)(k_8LWz_@D1=(op*8?eL`gx4gG^8YMg*h) zU33o@L?H@Fmr}YA0K|q|`|uggU3h~eYqPt(L9-UntTgw@-i=ajFI+)8iqLZyuhtP6 zf=*MH_kZ*Z=P!H@*F*!f`#|SYrF=*sAb$$XsM!WkrGOuV5hqSBVoX+y=6Oe&8vgO` zUSwr?9^(qX@r`fNPr8JGhf{=6RnRZX92_SbVk!{{X=3>Mzx{nym*;U^%dfxiO^lNP zQXH>Bnz-D!c9N*?p%6qtUIHjY1ohG%|Doi#RKcK}Mq$|J6u2!HfC zFA>MTP(ty%?-Er0sN7hxN24)@`n6yEy0mtFixcy&p;VVNP4L4OXU^W@oi}?-j5}O<+CvpWzV_;G z^X}zexhJYz{PMr@>~r5L6Ri?zrhmYZ5wY^WuYTtRF2D23_pI}!i~qt`p8Xp{AWMZ; zUWuvJeNLaVy#JqvP+1knf%Pp-YwsJVU;O!R%kJ)3W{>v{hrh~yCl5d=X*5L-OOA|hCuKf_vwqkoUx=G(8d z@O;D5U-3W`Y3B0sKl~{x%U?i!`NGYTmY(+pLHL)5Se|;S#`(u<{PREc*x5_&0g`*N zjQ-l6vK-8<9&lc$(eXT*Dx#^=EJ94DZzJEsR!U9^Ol|t#FJ@|dVIwQIt(YD17G+o?QByWqw4(3?P zwZ$cR$tur3U%|MRSHJTD@4h>vp8A8|`(05$6vte>_92&k`bmk;^eVo96$QV z{lORQ0j&melvc$#FcfeUpcOk5!j4iV@6X5g3vuK(1w0}~(@y@$^@xny_ zjH6RPar5RCAm;o3@iqWw=O5$fk;4TW1f_ERq9i|XWWZ?)Xsop;4caQK5)g|mB3mAX z3f_y1XnV-}{r6z)oE)bfeH4JVe)wJv+892*`T_IvXE9qlEz&F_PBmXVcb9- zMxDU(vDR|y&N3ffy-uS!O&Hd>edjg`K|6-4ORHSJwZ_JFi#Sec)T*RehMAjcl%Y*T zNYaemcApQfFMl)M2x+&snV6iV64nqDQ&V$%a(kI$N9IsUv2bIFv9U?~+7ym4OdWq3 z$MN}iVTqr5d|0TwcjYS0qnGf58foh$p5LI}$XHlhV(f`?hzLu!Zqpc>CJbwUVtitT zPgXWrTHT{w@i{U*hUYp(u*eTxy)QzDptYh|4>>a3pnuhkh*Fmz2+3@Q%~HZ3q|@yZ z$1!P=va)uUYIQ8nKBE>9lCfJV9;h4DR&LLNJFmRqk%A zlO`!?nzFmsA_yv2Yq2(^-RYwppTkoPCK?rtqe?#-gibv?R0e76z-i&oc$G@%v$D2H zmS$vGMt^243P_WLG)=H#=_M)RPT^FK6ZkG+rG~XBNfMJLF>xFfX@#cK?IX&dYp21V zLPSW@gfvNVRa%S9QZ~1?(F$fJsyJGe&Mh)bw?zb9cFMr(hZ7NK)&h)HtZi(O6*;~@ zxv7X?ohGJv9zoIVMfCbH6hbCRLYk%sLL4V3rGIGFD}=s>X`CzPrD>i4h|Mhl!gwPj zPudt_8$_o9qdwRnQcf$SZq`E(VRLJjG);<4Gm@fhnol5TT;ouyh8UgK$^#1J+RejX zmRYuTJ9PRnqVvKj8CXCm_S!wtEMubBbCfbNim~W7rAbEofCHvNgl0XU)s5KPZDWj2 zntvr|s}K~TG$KM2r^HECrUz*fmmw4&j?=uzaSgqGgcV8)bfc6YoCF0E^`Oi~%Fin! zyjSEk41i|j@EG-heUvH^o?75h4O|?r&hkd5On05F#?m2O7mJzSNg^q4h@lBC_2>oJuS1>DNkO zMx~JlNI6QW%v$=^r!sXBLE#7CzT~Y|4G4Tgzqd!b+bfOkIHo+A6;P@8_?}Cv-G4(( zU!-$u12>KF+<|58Lm3%lCPfykikf(!B^h;^(l>^b%B-c`PYGwA#`8kz^?)$&=tl{A z?LJB=I^Bp)HzKGs%0tZe40F{0*LB$1?$D1DI=z^7H_9_;$D=ayGj#8~j@Am}=)4{; z(C2y75GSZI`!@Sb%6=~&MgSqpgnw2q#h-c-r!qq(mfcpb1g?rjE1^dmXC&$He*i>r zN))$;DR5zlYUtCC6OtrDhcg7zPtscdA+^xpIr_fks1&v4K=EcY<`2LM`{~q+GWw}Q zF!u~jWwt!V2f#t$`-XZoKq+X{9JY2kL~+XfF5ffMt3D#os0VCrx9LX-PJiPJ6}Lfq z_1_6hO6a>d2PiWLO9OhDgE7Ap2B9CPbfN_9jT1idb7;3(0{1-^*EmFRnt#nZpk)B# zILuDhsaAZnRwPNr?bRLnQBn$5Mw7vZwQ!E=BhL}7eV?7y7L~vy^i8h)!Z*t5Pk}iY z^QHK-*zP5Wt`JOJK-W&7w0~1N>GVVmtu@vPzGqn9ZnL}B+oxgUXsp2MdW$sM0l?83 zWAp)QxHyiY*N@3En?rMJ1ar@lbr$JuU!k|xp%!`sp2Be+>+a--guUf@ta=eOGip&b0>+BOQvz9Ej_smT*i!A3ltZlZ~+3V({ p(GI#cPgprY*8YUn?gw=HT^dzCk5suU^WSUigwXHg8+emW4U^zUYE}RM delta 3368 zcmV+@4cGGV8sQs|OMm)FL_t(&-tC!Nj33us$3N%HncM%i_nSAq+i}vwaZ=(GFs8H( zg$VKjMesm^iiCKmcmjkXgrE|r5AeW4ACQo!)K*BSD3w6a21sZU5+!j$6SZ{`+v~O0 zUa!6P{onsHXXeMl%zyU3Ydc9nn?IGQWbYN&OCJ9Zp^v1%o}eWxK86_BD;@$Et+rh(cY)LY6#~v~x_2WeA23yS-fzs0 zX`TO#G9MX2KYteS%<|@LDQ=LKd@z~qeW^w2OJKXGv7;!ZGX*}7g4}hc2B^zj-ZPHw z&+ouwK)Qac_jgI-X0~1)LwZeQeI8l8gku~KA-VMf)cA1#bkaqc;4Z>{xY_$W)vkG_ zK!5sSbOxWtJ?z5kC~Z?vyC=Mv0HQ5{(lS4!NdtvWddm|BlQ~)cM#h{ zPkjPs>b|=<dx`Tcuy7WC95)x6YUpYsT zBm`pzaDS^4#ElhfXA4OpMyC%GmTHKkc#ftNcpu6A0G{jNxp#hM9HG}*qPsdzw_PXh zb#W(;;!hkW7@ggAdTWj5;(3}2?_j%4!pS34?m3AWu6P6F6sZWk=oZQHO+uqEt|l?U z`t|o19p6W}HjL3ejxOh~e7F+YF}Hg&O=)bcv46RGlU98LtsPv~!BNn?vPymKHN2r2 zD*GQ|>+&1K%{2ngp=vayYUtMI*?4;%qqTzwD3v)#qc8<%~Gxo?+`9YENNm%tOdvdJHI-u25Yw#sc)>}Iu5?8nH;O3cNs!NXm!_Uy!QeX zPk-T$R&sym*~fLMl)#A614dM!^5nIPpwWtI#VwvCNlGv7vN-=f#`7sxhG@6yblNSn z(kQJ^N^uP6bvoEMV&%qFqF#s4cbFKd;AmY4BxJVQ&NxD~JP>2DEqtzFCYK0EE_CJt zRgh39M6n%GO6LlIq#+m2f0_qQy+oWe*?-ztWw;VBTpGR&Ro5@Si&mPFuNf*=x3h?V zwH`ls`z#NhdJ$uy9ae@xjq?1HFDcbmfWhe2+txr4ggp-5JC89*{xnMk)*8O`&EI2b z@fgMxe*NjM(v91Mfrpc)QI*3l0Y3ZLOCTAS!iFMPYxsw+e~Fum$8lZZ*Pi++u78u{ zGGu#gY`A>!Fj3Dda;QQ`MS%$FnLqk{$re?PpbSP~*yYIaIbM2xnYjzi0$~VrTF($g zKUY}T^S(z=`by!yJ}4CMyKgP>H=n!*v=k)r(5BsdhBzLi^CDs8D?2Rz&?93!c4m~z z7ml&A++}Tbm0qvQ^vn#kp&`^4et+dxrLp;&96t5}O0}^z#t$2uxc?e&yxd`Q#No_Y z50xwV!t-C`&2zteTUI&!*uU_(&wpc}{Ac&%i*Mt6?cp6*2jTgDdx~>!{L*c79zFff zeCBgsLj)2leD^yM<(kj&2U33c-;=1MgySeyH#GIFr%^xuv(L%a*8NP+{(q2PeDce< zZk9P-e!j=#q~Y|VHLkpOfH?NhTBDRgss4TYM={=M=L3KFcP#wjZx@&r$ubO*fkZ@* zG`~xVh>)h)J*>3YfAl)feYc6{JDmND2codn<=fx-6K*WthkESPLIF$9dx;?Yb3{@; z^{EOEo~-as-|nzkk9XOrAAe9XINMnz^Jl;F=4Jl&(Ia=Q7uyLir?+e0^o-$&Cp=zw zp~a<(U6fKp-9M$IAwqKFF@&ofbbgg5`|5bwPE9!Cxw>%ICkt4nDxyDHc5!A=HUk(q*^ZFxeiL{+$wNmd4vLH4?a$-8-MfO`EyK;jpDk7@{8waoc#%wZr<~-6-bb+y#bfH3H8k zO;fJjSmgYLOVoxY3BxMam#(8k(2n84)tg*eSY~CtK@?ePl`=L-F*D<}BDIMKu}#=& zcKOkzMMi2N&E^K9W7Cwv3W8#Me1@yn7dbFHgHnpQ%YRoG8XCi|jN=%?_`$O{j?epZ zSNP<~`!f&3G4H&4f#Ll>jUQC8%>~?Gh-x)q?#etvCm%#axN_|pL&Fn*UEIE4sQU+qnW-D~78fvlBHM?H)br5(FVhnvf=zFbHY2+eA@> zjV(*dw|^*?hqCUo*Ps_!!m$UqadU|{&eCrbMYLOWYE!2ukDtID|0%?uM!RKht*l~W zi?x<|y@BtSNYj)wu{2vC_(23kyVIl7jSA=#SxAH^vM2?^)sWElaE4A6`)q!8kThkpQ3r&PS_r7^>dkib z&VQ2{diO#$94PaWF+_y5^)0N;g^Cm6d~AjvLeRLzp;8VpI_u;65b7&pj3G%<*0rbyK)xAP(5&DnuBr1~l3|*0!1$<71N;ohk%{ zD2<5Fi!4!`6zzeHqaF7svM8YSl^{4A*oska5CQh${4 zP)ZRV{w-F*QQ$kQl%Bvp^cX1~?WoUOA=)tVz?WEGc^%JO$1^&ULG_J3_+?It&ac0& z05hnK+(pYlNF`}XH}xrvpGHvlLAaxNtCRx*-_Y&UX|_86v^rfJ#}t)WDJTU#zUNYJ zcIZx=rgd!<*G71*Q=ETqgN*dM-haFcR{5D2cH(^pqy|z}lBP7fmT>wko)=QB284k} zw--}yX02|k-J{j+5tM3$^~%*6)6+hlYgpfG(e1^wIuXrw76;1lC{6t&?Hm7z)(Ye3 z>^z=J-$z7WPEbYnZFV$K?1asB1`v`&Xml+8_#-%_DH2K9YIF+0RZg@NdVfSwLTtDH zJ0C@swa6Cp{=p{Ri z=_PcnLooAcoYHhr#`}VU!uJi;a)44$t2nH0w&)EAJ$U(EwpS2pm4LO4Cf#0)Q#(P) ztcwbpgz%o9LA&KbaNl!rjYBW8`PV#4 zFKX@()Hqo^IB{eOtrf9NxW2SWw-*=YgucnFpT|aV z`cq(b=X?>N7h9U07||ty@l)u^VU%`?Ae|VkptUAV1>ZBQY&6-bcYk(R*f^RrH`Du< zZvo(FjWK$cH(VS?(e1|AB*{c`D+Du-leFgPY@DZ4Z&3+70?%YAcAz%whyj}<)LRi& zg?OW=$$uivIy4xPL28SqvSM-VBq{(~n00 From ada4e375564d72d2bf739ee0b46622fe590fbff6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 24 Nov 2014 01:02:18 +0100 Subject: [PATCH 08/98] Fix race preview texture not being destroyed properly (Fixes #2098) --- apps/openmw/mwgui/race.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 2bfc4f141..444b572b6 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -162,6 +162,9 @@ namespace MWGui void RaceDialog::close() { + mPreviewImage->setImageTexture(""); + const std::string textureName = "CharacterHeadPreview"; + MyGUI::RenderManager::getInstance().destroyTexture(MyGUI::RenderManager::getInstance().getTexture(textureName)); mPreview.reset(NULL); } From 69134e3ac27e6986c16a8cca68b99dcf6019a9a2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 24 Nov 2014 12:48:36 +1100 Subject: [PATCH 09/98] Add icon to windows executable. --- apps/wizard/CMakeLists.txt | 4 ++++ files/windows/openmw-wizard.ico | Bin 0 -> 370070 bytes files/windows/openmw-wizard.rc | 1 + 3 files changed, 5 insertions(+) create mode 100644 files/windows/openmw-wizard.ico create mode 100644 files/windows/openmw-wizard.rc diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 61d6c5123..b8cc3fda4 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -25,6 +25,10 @@ set(WIZARD utils/componentlistwidget.cpp ) +if(WIN32) + list(APPEND WIZARD ${CMAKE_SOURCE_DIR}/files/windows/openmw-wizard.rc) +endif() + set(WIZARD_HEADER componentselectionpage.hpp conclusionpage.hpp diff --git a/files/windows/openmw-wizard.ico b/files/windows/openmw-wizard.ico new file mode 100644 index 0000000000000000000000000000000000000000..e5dd50ba631ce5e65e90c7969ba2872356829880 GIT binary patch literal 370070 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�R#2v$r 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 Date: Tue, 25 Nov 2014 02:41:54 +0100 Subject: [PATCH 10/98] Apply the frame time cap to Ogre's ControllerManager (Fixes #2154) This fixes particle systems getting out of whack due to a particularly long frame time, e.g. after a loading screen. --- apps/openmw/engine.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2eebb8c28..d7b23c096 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -79,8 +79,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { - float frametime = std::min(evt.timeSinceLastFrame, 0.2f); - + float frametime = evt.timeSinceLastFrame; mEnvironment.setFrameDuration (frametime); // update input @@ -478,9 +477,15 @@ void OMW::Engine::go() } // Start the main rendering loop + Ogre::Timer timer; while (!MWBase::Environment::get().getStateManager()->hasQuitRequest()) - Ogre::Root::getSingleton().renderOneFrame(); + { + float dt = timer.getMilliseconds()/1000.f; + dt = std::min(dt, 0.2f); + timer.reset(); + Ogre::Root::getSingleton().renderOneFrame(dt); + } // Save user settings settings.saveUser(settingspath); From 238325455d6a15ae12e162ee796fae5fe8cab809 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 23 Nov 2014 12:40:55 +0100 Subject: [PATCH 11/98] Erase effects that have expired (Fixes #2134) --- apps/openmw/mwmechanics/activespells.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index e64a736c3..d87e22543 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -17,18 +17,35 @@ namespace MWMechanics MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp(); - // Erase no longer active spells + // Erase no longer active spells and effects if (mLastUpdate!=now) { TContainer::iterator iter (mSpells.begin()); while (iter!=mSpells.end()) + { if (!timeToExpire (iter)) { mSpells.erase (iter++); rebuild = true; } else + { + std::vector& effects = iter->second.mEffects; + for (std::vector::iterator effectIt = effects.begin(); effectIt != effects.end();) + { + MWWorld::TimeStamp start = iter->second.mTimeStamp; + MWWorld::TimeStamp end = start + static_cast(effectIt->mDuration)*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); + if (end <= now) + { + effectIt = effects.erase(effectIt); + rebuild = true; + } + else + ++effectIt; + } ++iter; + } + } mLastUpdate = now; } From ff8bdd74ed32e2b2151156cd9149648d94bb094e Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 25 Nov 2014 15:54:55 +0100 Subject: [PATCH 12/98] Fix strange bitflags handling --- apps/wizard/componentselectionpage.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/wizard/componentselectionpage.cpp b/apps/wizard/componentselectionpage.cpp index d372f677d..956f0f237 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -62,7 +62,7 @@ void Wizard::ComponentSelectionPage::initializePage() if (field(QLatin1String("installation.new")).toBool() == true) { - morrowindItem->setFlags(morrowindItem->flags() & !Qt::ItemIsEnabled & Qt::ItemIsUserCheckable); + morrowindItem->setFlags(morrowindItem->flags() & ~Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); morrowindItem->setData(Qt::CheckStateRole, Qt::Checked); componentsList->addItem(morrowindItem); @@ -77,7 +77,7 @@ void Wizard::ComponentSelectionPage::initializePage() if (mWizard->mInstallations[path].hasMorrowind) { morrowindItem->setText(tr("Morrowind\t\t(installed)")); - morrowindItem->setFlags(morrowindItem->flags() & !Qt::ItemIsEnabled & Qt::ItemIsUserCheckable); + morrowindItem->setFlags(morrowindItem->flags() & ~Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); morrowindItem->setData(Qt::CheckStateRole, Qt::Unchecked); } else { morrowindItem->setText(tr("Morrowind")); @@ -88,7 +88,7 @@ void Wizard::ComponentSelectionPage::initializePage() if (mWizard->mInstallations[path].hasTribunal) { tribunalItem->setText(tr("Tribunal\t\t(installed)")); - tribunalItem->setFlags(tribunalItem->flags() & !Qt::ItemIsEnabled & Qt::ItemIsUserCheckable); + tribunalItem->setFlags(tribunalItem->flags() & ~Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); tribunalItem->setData(Qt::CheckStateRole, Qt::Unchecked); } else { tribunalItem->setText(tr("Tribunal")); @@ -99,7 +99,7 @@ void Wizard::ComponentSelectionPage::initializePage() if (mWizard->mInstallations[path].hasBloodmoon) { bloodmoonItem->setText(tr("Bloodmoon\t\t(installed)")); - bloodmoonItem->setFlags(bloodmoonItem->flags() & !Qt::ItemIsEnabled & Qt::ItemIsUserCheckable); + bloodmoonItem->setFlags(bloodmoonItem->flags() & ~Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); bloodmoonItem->setData(Qt::CheckStateRole, Qt::Unchecked); } else { bloodmoonItem->setText(tr("Bloodmoon")); From 936094ae950897fe43f64809b3ed025bc7987d2a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 26 Nov 2014 08:08:28 +1100 Subject: [PATCH 13/98] Set range of spinbox types in dialogsubview. --- apps/opencs/view/world/util.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index f8847abfc..f987c8d9f 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -2,6 +2,8 @@ #include "util.hpp" #include +#include +#include #include #include @@ -157,16 +159,22 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return new QLineEdit(parent); case CSMWorld::ColumnBase::Display_Integer: - - return new QSpinBox(parent); + { + QSpinBox *sb = new QSpinBox(parent); + sb->setRange(INT_MIN, INT_MAX); + return sb; + } case CSMWorld::ColumnBase::Display_Var: return new QLineEdit(parent); case CSMWorld::ColumnBase::Display_Float: - - return new QDoubleSpinBox(parent); + { + QDoubleSpinBox *dsb = new QDoubleSpinBox(parent); + dsb->setRange(FLT_MIN, FLT_MAX); + return dsb; + } case CSMWorld::ColumnBase::Display_LongString: { From 54ac54b347ae9edc32f70336c72303d1c03f0869 Mon Sep 17 00:00:00 2001 From: Sergey Shnatsel Davidoff Date: Wed, 26 Nov 2014 00:20:45 +0300 Subject: [PATCH 14/98] Add the "scene-play.png" icon for launching the game from OpenCS. Also included are SVG source and the GIMP XCF with transparency mask on the edges. --- .../opencs/raster/scene-play-rev9_masked.xcf | Bin 0 -> 8365 bytes files/opencs/scalable/scene-play-rev9.svg | 972 ++++++++++++++++++ files/opencs/scene-play.png | Bin 0 -> 3601 bytes 3 files changed, 972 insertions(+) create mode 100644 files/opencs/raster/scene-play-rev9_masked.xcf create mode 100644 files/opencs/scalable/scene-play-rev9.svg create mode 100644 files/opencs/scene-play.png diff --git a/files/opencs/raster/scene-play-rev9_masked.xcf b/files/opencs/raster/scene-play-rev9_masked.xcf new file mode 100644 index 0000000000000000000000000000000000000000..4f7a06d065d343b98b179e3141b71b43800695db GIT binary patch literal 8365 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 literal 0 HcmV?d00001 diff --git a/files/opencs/scalable/scene-play-rev9.svg b/files/opencs/scalable/scene-play-rev9.svg new file mode 100644 index 000000000..59a479310 --- /dev/null +++ b/files/opencs/scalable/scene-play-rev9.svg @@ -0,0 +1,972 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-play.png b/files/opencs/scene-play.png new file mode 100644 index 0000000000000000000000000000000000000000..e2fabea7d9f80d5820085428ba5b82a0fc0e8b8a GIT binary patch literal 3601 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 XE>yyZSdFAp00000NkvXXu0mjfgA3Z> literal 0 HcmV?d00001 From f1ff2b2d6a4456da80edeb0b58f881dd46410dc7 Mon Sep 17 00:00:00 2001 From: Sergey Shnatsel Davidoff Date: Wed, 26 Nov 2014 00:28:11 +0300 Subject: [PATCH 15/98] Add offscreen credits and a note about the use of "Play" icon from elementary icon theme to the SVG masters. Clean up unused offscreen objects in scene view icon. --- files/opencs/scalable/scene-play-rev9.svg | 48 ++++++++++++--- .../scalable/scene-view-status-rev14.svg | 59 ++++++++++--------- 2 files changed, 71 insertions(+), 36 deletions(-) diff --git a/files/opencs/scalable/scene-play-rev9.svg b/files/opencs/scalable/scene-play-rev9.svg index 59a479310..26e7de1e8 100644 --- a/files/opencs/scalable/scene-play-rev9.svg +++ b/files/opencs/scalable/scene-play-rev9.svg @@ -15,7 +15,7 @@ id="svg2" version="1.1" inkscape:version="0.48.3.1 r9886" - sodipodi:docname="14_play9_.svg"> + sodipodi:docname="scene-play-rev9.svg"> + + + Sergey "Shnatsel" Davidoff <shnatsel@gmail.com> + + + + + Sergey "Shnatsel" Davidoff <shnatsel@gmail.com> + + + @@ -947,8 +959,7 @@ + inkscape:label="play"> @@ -968,5 +979,28 @@ inkscape:connector-curvature="0" d="m 4.5035809,44.49642 0,-39.9928394 L 43.49642,24.500001 4.5035809,44.49642 z" /> + the "play" sign is taken fromelementary icon themeby Daniel Forelicensed under GNU GPLv3 diff --git a/files/opencs/scalable/scene-view-status-rev14.svg b/files/opencs/scalable/scene-view-status-rev14.svg index bb2eab25d..0724babe7 100644 --- a/files/opencs/scalable/scene-view-status-rev14.svg +++ b/files/opencs/scalable/scene-view-status-rev14.svg @@ -273,12 +273,12 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="16" - inkscape:cx="2.950497" - inkscape:cy="24.209766" + inkscape:zoom="4" + inkscape:cx="19.041611" + inkscape:cy="-5.7168931" inkscape:document-units="px" inkscape:current-layer="layer3" - showgrid="true" + showgrid="false" inkscape:snap-page="true" showguides="true" inkscape:guide-bbox="true" @@ -309,7 +309,7 @@ image/svg+xml - + Sergey "Shnatsel" Davidoff <shnatsel@gmail.com> @@ -332,28 +332,6 @@ transform="translate(0,-1004.3622)" style="display:inline" sodipodi:insensitive="true"> - - - - + This icon was designed bySergey "Shnatsel" Davidofffor OpenMW content editorLicensed under GNU GPLv3 + style="display:inline" + sodipodi:insensitive="true"> Date: Thu, 27 Nov 2014 08:59:21 +0100 Subject: [PATCH 16/98] fixed missing tooltip update for toggle/mode-type buttons --- apps/opencs/view/widget/pushbutton.cpp | 10 ++++++++++ apps/opencs/view/widget/pushbutton.hpp | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index f23462585..d4e600794 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -72,6 +72,11 @@ CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const QString& QWidget *parent) : QPushButton (icon, "", parent), mKeepOpen (false), mType (type), mToolTip (tooltip) { + if (type==Type_Mode || type==Type_Toggle) + { + setCheckable (true); + connect (this, SIGNAL (toggled (bool)), this, SLOT (checkedStateChanged (bool))); + } setCheckable (type==Type_Mode || type==Type_Toggle); setExtendedToolTip(); } @@ -96,4 +101,9 @@ QString CSVWidget::PushButton::getBaseToolTip() const CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const { return mType; +} + +void CSVWidget::PushButton::checkedStateChanged (bool checked) +{ + setExtendedToolTip(); } \ No newline at end of file diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 35062a137..09cf22757 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -53,6 +53,10 @@ namespace CSVWidget QString getBaseToolTip() const; Type getType() const; + + private slots: + + void checkedStateChanged (bool checked); }; } From 50a489321fbc5c4bbc91652de9cd9ffc5306a813 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 27 Nov 2014 09:27:29 +0100 Subject: [PATCH 17/98] updated run button --- apps/opencs/view/render/worldspacewidget.cpp | 2 +- apps/opencs/view/widget/scenetoolrun.cpp | 8 ++++---- apps/opencs/view/widget/scenetoolrun.hpp | 4 +--- files/opencs/resources.qrc | 1 + 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 6c6acd22d..a5d1ba546 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -172,7 +172,7 @@ CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool ( std::sort (profiles.begin(), profiles.end()); mRun = new CSVWidget::SceneToolRun (parent, "Run OpenMW from the current camera position", - ":placeholder", ":placeholder", profiles); + ":scenetoolbar/play", profiles); connect (mRun, SIGNAL (runRequest (const std::string&)), this, SLOT (runRequest (const std::string&))); diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index 92f3193fe..0c7a4b9f0 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -26,7 +26,7 @@ void CSVWidget::SceneToolRun::adjustToolTips() void CSVWidget::SceneToolRun::updateIcon() { - setIcon (QIcon (mSelected==mProfiles.end() ? mIconDisabled : mIcon)); + setDisabled (mSelected==mProfiles.end()); } void CSVWidget::SceneToolRun::updatePanel() @@ -46,11 +46,11 @@ void CSVWidget::SceneToolRun::updatePanel() } CSVWidget::SceneToolRun::SceneToolRun (SceneToolbar *parent, const QString& toolTip, - const QString& icon, const QString& iconDisabled, const std::vector& profiles) + const QString& icon, const std::vector& profiles) : SceneTool (parent, Type_TopAction), mProfiles (profiles.begin(), profiles.end()), - mSelected (mProfiles.begin()), mToolTip (toolTip), mIcon (icon), - mIconDisabled (iconDisabled) + mSelected (mProfiles.begin()), mToolTip (toolTip) { + setIcon (QIcon (icon)); updateIcon(); adjustToolTips(); diff --git a/apps/opencs/view/widget/scenetoolrun.hpp b/apps/opencs/view/widget/scenetoolrun.hpp index 4396c2288..dd035462f 100644 --- a/apps/opencs/view/widget/scenetoolrun.hpp +++ b/apps/opencs/view/widget/scenetoolrun.hpp @@ -19,8 +19,6 @@ namespace CSVWidget std::set mProfiles; std::set::iterator mSelected; QString mToolTip; - QString mIcon; - QString mIconDisabled; QFrame *mPanel; QTableWidget *mTable; @@ -35,7 +33,7 @@ namespace CSVWidget public: SceneToolRun (SceneToolbar *parent, const QString& toolTip, const QString& icon, - const QString& iconDisabled, const std::vector& profiles); + const std::vector& profiles); virtual void showPanel (const QPoint& position); diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 751ae6484..86631f437 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -79,5 +79,6 @@ eyeballdude.png flying eye.png orbit2.png + scene-play.png From cb74c1c36e24debbd697f16fd7fd3d2d619bbdbf Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Thu, 27 Nov 2014 20:44:41 +0100 Subject: [PATCH 18/98] Set health to 0 if it drops below 1 (Fixes #2163) --- apps/openmw/mwmechanics/creaturestats.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index c4d316ad6..a287a7e11 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -184,6 +184,7 @@ namespace MWMechanics if (index==0 && mDynamic[index].getCurrent()<1) { mDead = true; + mDynamic[index].setCurrent(0); if (MWBase::Environment::get().getWorld()->getGodModeState()) MWBase::Environment::get().getMechanicsManager()->keepPlayerAlive(); From e04ead2bd53c42a081a8978fb5b3eb3652b46776 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 28 Nov 2014 09:14:02 +0100 Subject: [PATCH 19/98] new element visibility button icons --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/view/render/elements.hpp | 6 +- .../view/render/pagedworldspacewidget.hpp | 6 +- .../view/render/unpagedworldspacewidget.cpp | 5 +- .../view/render/unpagedworldspacewidget.hpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 18 +-- apps/opencs/view/render/worldspacewidget.hpp | 8 +- apps/opencs/view/widget/scenetooltoggle2.cpp | 139 ++++++++++++++++++ apps/opencs/view/widget/scenetooltoggle2.hpp | 76 ++++++++++ apps/opencs/view/world/scenesubview.cpp | 3 +- files/opencs/resources.qrc | 37 +++++ 11 files changed, 280 insertions(+), 21 deletions(-) create mode 100644 apps/opencs/view/widget/scenetooltoggle2.cpp create mode 100644 apps/opencs/view/widget/scenetooltoggle2.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 969058dd7..9d8dd89e1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -73,6 +73,7 @@ opencs_units_noqt (view/world opencs_units (view/widget scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton + scenetooltoggle2 ) opencs_units (view/render diff --git a/apps/opencs/view/render/elements.hpp b/apps/opencs/view/render/elements.hpp index 784e41212..5a37956e9 100644 --- a/apps/opencs/view/render/elements.hpp +++ b/apps/opencs/view/render/elements.hpp @@ -8,10 +8,10 @@ namespace CSVRender { // elements that are part of the actual scene Element_Reference = 0x1, - Element_Terrain = 0x2, + Element_Pathgrid = 0x2, Element_Water = 0x4, - Element_Pathgrid = 0x8, - Element_Fog = 0x10, + Element_Fog = 0x8, + Element_Terrain = 0x10, // control elements Element_CellMarker = 0x10000, diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 59540a71e..ca618d122 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -8,9 +8,13 @@ #include "worldspacewidget.hpp" #include "cell.hpp" +namespace CSVWidget +{ + class SceneToolToggle; +} + namespace CSVRender { - class TextOverlay; class OverlayMask; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 8012b1b24..1d6dd82c5 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -15,6 +15,7 @@ #include "../../model/world/tablemimedata.hpp" #include "../widget/scenetooltoggle.hpp" +#include "../widget/scenetooltoggle2.hpp" #include "elements.hpp" @@ -33,11 +34,11 @@ void CSVRender::UnpagedWorldspaceWidget::update() } void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( - CSVWidget::SceneToolToggle *tool) + CSVWidget::SceneToolToggle2 *tool) { WorldspaceWidget::addVisibilitySelectorButtons (tool); - tool->addButton (":armor.png", Element_Fog, ":armor.png", "Fog"); + tool->addButton (Element_Fog, "Fog"); } CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 5924abaa9..1463e5324 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -34,7 +34,7 @@ namespace CSVRender protected: - virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool); + virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); public: diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index a5d1ba546..993c77688 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -13,7 +13,7 @@ #include "../../model/world/idtable.hpp" #include "../widget/scenetoolmode.hpp" -#include "../widget/scenetooltoggle.hpp" +#include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" #include "../world/physicsmanager.hpp" @@ -127,10 +127,10 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( return tool; } -CSVWidget::SceneToolToggle *CSVRender::WorldspaceWidget::makeSceneVisibilitySelector (CSVWidget::SceneToolbar *parent) +CSVWidget::SceneToolToggle2 *CSVRender::WorldspaceWidget::makeSceneVisibilitySelector (CSVWidget::SceneToolbar *parent) { - mSceneElements= new CSVWidget::SceneToolToggle (parent, - "Scene Element Visibility", ":placeholder"); + mSceneElements = new CSVWidget::SceneToolToggle2 (parent, + "Scene Element Visibility", ":scenetoolbar/scene-view-c", ":scenetoolbar/scene-view-"); addVisibilitySelectorButtons (mSceneElements); @@ -260,12 +260,12 @@ unsigned int CSVRender::WorldspaceWidget::getInteractionMask() const } void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( - CSVWidget::SceneToolToggle *tool) + CSVWidget::SceneToolToggle2 *tool) { - tool->addButton (":placeholder", Element_Reference, ":placeholder", "References"); - tool->addButton (":placeholder", Element_Terrain, ":placeholder", "Terrain"); - tool->addButton (":placeholder", Element_Water, ":placeholder", "Water"); - tool->addButton (":placeholder", Element_Pathgrid, ":placeholder", "Pathgrid"); + tool->addButton (Element_Reference, "References"); + tool->addButton (Element_Terrain, "Terrain"); + tool->addButton (Element_Water, "Water"); + tool->addButton (Element_Pathgrid, "Pathgrid"); } void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index e54eb91e1..550b5d4a9 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -18,7 +18,7 @@ namespace CSMWorld namespace CSVWidget { class SceneToolMode; - class SceneToolToggle; + class SceneToolToggle2; class SceneToolbar; class SceneToolRun; } @@ -37,7 +37,7 @@ namespace CSVRender CSVRender::Navigation1st m1st; CSVRender::NavigationFree mFree; CSVRender::NavigationOrbit mOrbit; - CSVWidget::SceneToolToggle *mSceneElements; + CSVWidget::SceneToolToggle2 *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; CSVWorld::PhysicsSystem *mPhysics; @@ -71,7 +71,7 @@ namespace CSVRender /// \attention The created tool is not added to the toolbar (via addTool). Doing /// that is the responsibility of the calling function. - CSVWidget::SceneToolToggle *makeSceneVisibilitySelector ( + CSVWidget::SceneToolToggle2 *makeSceneVisibilitySelector ( CSVWidget::SceneToolbar *parent); /// \attention The created tool is not added to the toolbar (via addTool). Doing @@ -107,7 +107,7 @@ namespace CSVRender protected: - virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool); + virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); diff --git a/apps/opencs/view/widget/scenetooltoggle2.cpp b/apps/opencs/view/widget/scenetooltoggle2.cpp new file mode 100644 index 000000000..1c5c11a4d --- /dev/null +++ b/apps/opencs/view/widget/scenetooltoggle2.cpp @@ -0,0 +1,139 @@ + +#include "scenetooltoggle2.hpp" + +#include +#include + +#include +#include +#include +#include + +#include "scenetoolbar.hpp" +#include "pushbutton.hpp" + +void CSVWidget::SceneToolToggle2::adjustToolTip() +{ + QString toolTip = mToolTip; + + toolTip += "

Currently enabled: "; + + bool first = true; + + for (std::map::const_iterator iter (mButtons.begin()); + iter!=mButtons.end(); ++iter) + if (iter->first->isChecked()) + { + if (!first) + toolTip += ", "; + else + first = false; + + toolTip += iter->second.mName; + } + + if (first) + toolTip += "none"; + + toolTip += "

(left click to alter selection)"; + + setToolTip (toolTip); +} + +void CSVWidget::SceneToolToggle2::adjustIcon() +{ + std::ostringstream stream; + stream << mCompositeIcon << getSelection(); + setIcon (QIcon (QString::fromUtf8 (stream.str().c_str()))); +} + +CSVWidget::SceneToolToggle2::SceneToolToggle2 (SceneToolbar *parent, const QString& toolTip, + const std::string& compositeIcon, const std::string& singleIcon) +: SceneTool (parent), mCompositeIcon (compositeIcon), mSingleIcon (singleIcon), + mButtonSize (parent->getButtonSize()), mIconSize (parent->getIconSize()), mToolTip (toolTip), + mFirst (0) +{ + mPanel = new QFrame (this, Qt::Popup); + + mLayout = new QHBoxLayout (mPanel); + + mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); + + mPanel->setLayout (mLayout); +} + +void CSVWidget::SceneToolToggle2::showPanel (const QPoint& position) +{ + mPanel->move (position); + mPanel->show(); + + if (mFirst) + mFirst->setFocus (Qt::OtherFocusReason); +} + +void CSVWidget::SceneToolToggle2::addButton (unsigned int id, + const QString& name, const QString& tooltip) +{ + std::ostringstream stream; + stream << mSingleIcon << id; + + PushButton *button = new PushButton (QIcon (QPixmap (stream.str().c_str())), + PushButton::Type_Toggle, tooltip.isEmpty() ? name: tooltip, mPanel); + + button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + button->setIconSize (QSize (mIconSize, mIconSize)); + button->setFixedSize (mButtonSize, mButtonSize); + + mLayout->addWidget (button); + + ButtonDesc desc; + desc.mId = id; + desc.mName = name; + desc.mIndex = mButtons.size(); + + mButtons.insert (std::make_pair (button, desc)); + + connect (button, SIGNAL (clicked()), this, SLOT (selected())); + + if (mButtons.size()==1) + mFirst = button; +} + +unsigned int CSVWidget::SceneToolToggle2::getSelection() const +{ + unsigned int selection = 0; + + for (std::map::const_iterator iter (mButtons.begin()); + iter!=mButtons.end(); ++iter) + if (iter->first->isChecked()) + selection |= iter->second.mId; + + return selection; +} + +void CSVWidget::SceneToolToggle2::setSelection (unsigned int selection) +{ + for (std::map::iterator iter (mButtons.begin()); + iter!=mButtons.end(); ++iter) + iter->first->setChecked (selection & iter->second.mId); + + adjustToolTip(); + adjustIcon(); +} + +void CSVWidget::SceneToolToggle2::selected() +{ + std::map::const_iterator iter = + mButtons.find (dynamic_cast (sender())); + + if (iter!=mButtons.end()) + { + if (!iter->first->hasKeepOpen()) + mPanel->hide(); + + adjustToolTip(); + adjustIcon(); + + emit selectionChanged(); + } +} diff --git a/apps/opencs/view/widget/scenetooltoggle2.hpp b/apps/opencs/view/widget/scenetooltoggle2.hpp new file mode 100644 index 000000000..4bd9ba26f --- /dev/null +++ b/apps/opencs/view/widget/scenetooltoggle2.hpp @@ -0,0 +1,76 @@ +#ifndef CSV_WIDGET_SCENETOOL_TOGGLE2_H +#define CSV_WIDGET_SCENETOOL_TOGGLE2_H + +#include "scenetool.hpp" + +#include + +class QHBoxLayout; +class QRect; + +namespace CSVWidget +{ + class SceneToolbar; + class PushButton; + + ///< \brief Multi-Toggle tool + /// + /// Top level button is using predefined icons instead building a composite icon. + class SceneToolToggle2 : public SceneTool + { + Q_OBJECT + + struct ButtonDesc + { + unsigned int mId; + QString mName; + int mIndex; + }; + + std::string mCompositeIcon; + std::string mSingleIcon; + QWidget *mPanel; + QHBoxLayout *mLayout; + std::map mButtons; // widget, id + int mButtonSize; + int mIconSize; + QString mToolTip; + PushButton *mFirst; + + void adjustToolTip(); + + void adjustIcon(); + + public: + + /// The top level icon is compositeIcon + sum of bitpatterns for active buttons (in + /// decimal) + /// + /// The icon for individual toggle buttons is signleIcon + bitmask for button (in + /// decimal) + SceneToolToggle2 (SceneToolbar *parent, const QString& toolTip, + const std::string& compositeIcon, const std::string& singleIcon); + + virtual void showPanel (const QPoint& position); + + /// \attention After the last button has been added, setSelection must be called at + /// least once to finalise the layout. + void addButton (unsigned int id, + const QString& name, const QString& tooltip = ""); + + unsigned int getSelection() const; + + /// \param or'ed button IDs. IDs that do not exist will be ignored. + void setSelection (unsigned int selection); + + signals: + + void selectionChanged(); + + private slots: + + void selected(); + }; +} + +#endif diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 5ddefcc6b..3fdf2f6e5 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -20,6 +20,7 @@ #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle.hpp" +#include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" #include "tablebottombox.hpp" @@ -109,7 +110,7 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp CSVWidget::SceneToolMode *lightingTool = widget->makeLightingSelector (toolbar); toolbar->addTool (lightingTool); - CSVWidget::SceneToolToggle *sceneVisibilityTool = + CSVWidget::SceneToolToggle2 *sceneVisibilityTool = widget->makeSceneVisibilitySelector (toolbar); toolbar->addTool (sceneVisibilityTool); diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index 86631f437..0cc6996a8 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -80,5 +80,42 @@ flying eye.png orbit2.png scene-play.png + scene-view-references.png + scene-view-terrain.png + scene-view-water.png + scene-view-pathgrid.png + scene-view-fog.png + scene-view-status-0.png + scene-view-status-1.png + scene-view-status-2.png + scene-view-status-3.png + scene-view-status-4.png + scene-view-status-5.png + scene-view-status-6.png + scene-view-status-7.png + scene-view-status-8.png + scene-view-status-9.png + scene-view-status-10.png + scene-view-status-11.png + scene-view-status-12.png + scene-view-status-13.png + scene-view-status-14.png + scene-view-status-15.png + scene-view-status-16.png + scene-view-status-17.png + scene-view-status-18.png + scene-view-status-19.png + scene-view-status-20.png + scene-view-status-21.png + scene-view-status-22.png + scene-view-status-23.png + scene-view-status-24.png + scene-view-status-25.png + scene-view-status-26.png + scene-view-status-27.png + scene-view-status-28.png + scene-view-status-29.png + scene-view-status-30.png + scene-view-status-31.png From e177b66c1d5cfec147bc892171f5ac0feec3f56f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 28 Nov 2014 09:16:39 +0100 Subject: [PATCH 20/98] moved fog button from unpaged worldspace to worldspace --- apps/opencs/view/render/unpagedworldspacewidget.cpp | 8 -------- apps/opencs/view/render/unpagedworldspacewidget.hpp | 4 ---- apps/opencs/view/render/worldspacewidget.cpp | 1 + 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 1d6dd82c5..07acbe493 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -33,14 +33,6 @@ void CSVRender::UnpagedWorldspaceWidget::update() flagAsModified(); } -void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( - CSVWidget::SceneToolToggle2 *tool) -{ - WorldspaceWidget::addVisibilitySelectorButtons (tool); - - tool->addButton (Element_Fog, "Fog"); -} - CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent) : WorldspaceWidget (document, parent), mCellId (cellId) { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 1463e5324..237cb8f46 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -32,10 +32,6 @@ namespace CSVRender void update(); - protected: - - virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); - public: UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 993c77688..1f7c41512 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -266,6 +266,7 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( tool->addButton (Element_Terrain, "Terrain"); tool->addButton (Element_Water, "Water"); tool->addButton (Element_Pathgrid, "Pathgrid"); + tool->addButton (Element_Fog, "Fog"); } void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) From 0a466ad643887b8fe1fdd0770736652a1dae2904 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 28 Nov 2014 14:45:35 +0100 Subject: [PATCH 21/98] Make recalculation of magicka less aggressive (Fixes #2155) --- apps/openmw/mwmechanics/actors.cpp | 9 ------ apps/openmw/mwmechanics/creaturestats.cpp | 34 +++++++++++++++-------- apps/openmw/mwmechanics/creaturestats.hpp | 3 +- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2e835d57e..a3cfbfd49 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -396,11 +396,7 @@ namespace MWMechanics { CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr); - int strength = creatureStats.getAttribute(ESM::Attribute::Strength).getModified(); int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified(); - int willpower = creatureStats.getAttribute(ESM::Attribute::Willpower).getModified(); - int agility = creatureStats.getAttribute(ESM::Attribute::Agility).getModified(); - int endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getModified(); float base = 1.f; if (ptr.getCellRef().getRefId() == "player") @@ -415,11 +411,6 @@ namespace MWMechanics float diff = (static_cast(magickaFactor*intelligence)) - magicka.getBase(); magicka.modify(diff); creatureStats.setMagicka(magicka); - - DynamicStat fatigue = creatureStats.getFatigue(); - diff = (strength+willpower+agility+endurance) - fatigue.getBase(); - fatigue.modify(diff); - creatureStats.setFatigue(fatigue); } void Actors::restoreDynamicStats (const MWWorld::Ptr& ptr, bool sleep) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index c4d316ad6..6d342833e 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -20,7 +20,7 @@ namespace MWMechanics mAttacked (false), mAttackingOrSpell(false), mIsWerewolf(false), - mFallHeight(0), mRecalcDynamicStats(false), mKnockdown(false), mKnockdownOneFrame(false), + mFallHeight(0), mRecalcMagicka(false), mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mDrawState (DrawState_Nothing), mAttackStrength(0.f), mLastRestock(0,0), mGoldPool(0), mActorId(-1), @@ -147,10 +147,22 @@ namespace MWMechanics if (value != currentValue) { - if (index != ESM::Attribute::Luck - && index != ESM::Attribute::Personality - && index != ESM::Attribute::Speed) - mRecalcDynamicStats = true; + if (index == ESM::Attribute::Intelligence) + mRecalcMagicka = true; + else if (index == ESM::Attribute::Strength || + index == ESM::Attribute::Willpower || + index == ESM::Attribute::Agility || + index == ESM::Attribute::Endurance) + { + int strength = getAttribute(ESM::Attribute::Strength).getModified(); + int willpower = getAttribute(ESM::Attribute::Willpower).getModified(); + int agility = getAttribute(ESM::Attribute::Agility).getModified(); + int endurance = getAttribute(ESM::Attribute::Endurance).getModified(); + DynamicStat fatigue = getFatigue(); + float diff = (strength+willpower+agility+endurance) - fatigue.getBase(); + fatigue.modify(diff); + setFatigue(fatigue); + } } if(!mIsWerewolf) @@ -199,7 +211,7 @@ namespace MWMechanics { if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier() != mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).getModifier()) - mRecalcDynamicStats = true; + mRecalcMagicka = true; mMagicEffects.setModifiers(effects); } @@ -360,9 +372,9 @@ namespace MWMechanics bool CreatureStats::needToRecalcDynamicStats() { - if (mRecalcDynamicStats) + if (mRecalcMagicka) { - mRecalcDynamicStats = false; + mRecalcMagicka = false; return true; } return false; @@ -370,7 +382,7 @@ namespace MWMechanics void CreatureStats::setNeedRecalcDynamicStats(bool val) { - mRecalcDynamicStats = val; + mRecalcMagicka = val; } void CreatureStats::setKnockedDown(bool value) @@ -497,7 +509,7 @@ namespace MWMechanics state.mAttackStrength = mAttackStrength; state.mFallHeight = mFallHeight; // TODO: vertical velocity (move from PhysicActor to CreatureStats?) state.mLastHitObject = mLastHitObject; - state.mRecalcDynamicStats = mRecalcDynamicStats; + state.mRecalcDynamicStats = mRecalcMagicka; state.mDrawState = mDrawState; state.mLevel = mLevel; state.mActorId = mActorId; @@ -545,7 +557,7 @@ namespace MWMechanics mAttackStrength = state.mAttackStrength; mFallHeight = state.mFallHeight; mLastHitObject = state.mLastHitObject; - mRecalcDynamicStats = state.mRecalcDynamicStats; + mRecalcMagicka = state.mRecalcDynamicStats; mDrawState = DrawState_(state.mDrawState); mLevel = state.mLevel; mActorId = state.mActorId; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 5e169ffb0..f830dd310 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -53,8 +53,7 @@ namespace MWMechanics std::string mLastHitObject; // The last object to hit this actor - // Do we need to recalculate stats derived from attributes or other factors? - bool mRecalcDynamicStats; + bool mRecalcMagicka; // For merchants: the last time items were restocked and gold pool refilled. MWWorld::TimeStamp mLastRestock; From d7220cdc2fd45f196467aed8ee4fbe23741df211 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 28 Nov 2014 14:48:03 +0100 Subject: [PATCH 22/98] Do not allow decrease below zero in modCurrentMagicka and modCurrentHealth (Fixes #2158) --- apps/openmw/mwscript/statsextensions.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index befb8d82e..d5647db10 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -278,7 +278,9 @@ namespace MWScript MWMechanics::DynamicStat stat (ptr.getClass().getCreatureStats (ptr) .getDynamic (mIndex)); - stat.setCurrent (diff + current, true); + // for fatigue, a negative current value is allowed and means the actor will be knocked down + bool allowDecreaseBelowZero = (mIndex == 2); + stat.setCurrent (diff + current, allowDecreaseBelowZero); ptr.getClass().getCreatureStats (ptr).setDynamic (mIndex, stat); } From ea8f617508ceb536225c8a097c6bcc1bf7b7b7f0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 28 Nov 2014 15:54:38 +0100 Subject: [PATCH 23/98] Add missing player control enabled checks (Fixes #2152) --- apps/openmw/mwinput/inputmanagerimp.cpp | 28 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6cb3a5ec5..68682abea 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -190,14 +190,12 @@ namespace MWInput int action = channel->getNumber(); - if (action == A_Use) + if (mControlSwitch["playercontrols"]) { - mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue); - } - - if (action == A_Jump) - { - mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); + if (action == A_Use) + mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue); + else if (action == A_Jump) + mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); } if (currentValue == 1) @@ -622,7 +620,7 @@ namespace MWInput mPlayer->pitch(y); } - if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change + if (arg.zrel && mControlSwitch["playerviewswitch"] && mControlSwitch["playercontrols"]) //Check to make sure you are allowed to zoomout and there is a change { MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.zrel); MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); @@ -680,7 +678,7 @@ namespace MWInput if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; // Not allowed before the magic window is accessible - if (!mControlSwitch["playermagic"]) + if (!mControlSwitch["playermagic"] || !mControlSwitch["playercontrols"]) return; // Not allowed if no spell selected @@ -701,7 +699,7 @@ namespace MWInput if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; // Not allowed before the inventory window is accessible - if (!mControlSwitch["playerfighting"]) + if (!mControlSwitch["playerfighting"] || !mControlSwitch["playercontrols"]) return; MWMechanics::DrawState_ state = mPlayer->getDrawState(); @@ -713,6 +711,9 @@ namespace MWInput void InputManager::rest() { + if (!mControlSwitch["playercontrols"]) + return; + if (!MWBase::Environment::get().getWindowManager()->getRestEnabled () || MWBase::Environment::get().getWindowManager()->isGuiMode ()) return; @@ -734,6 +735,9 @@ namespace MWInput void InputManager::toggleInventory() { + if (!mControlSwitch["playercontrols"]) + return; + if (MyGUI::InputManager::getInstance ().isModalAny()) return; @@ -770,6 +774,8 @@ namespace MWInput void InputManager::toggleJournal() { + if (!mControlSwitch["playercontrols"]) + return; if (MyGUI::InputManager::getInstance ().isModalAny()) return; @@ -787,6 +793,8 @@ namespace MWInput void InputManager::quickKey (int index) { + if (!mControlSwitch["playercontrols"]) + return; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if (player.getClass().getNpcStats(player).isWerewolf()) { From 4fd3a994e9eb199ce8154ac9fba0f22242824e54 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 28 Nov 2014 16:02:43 +0100 Subject: [PATCH 24/98] Add model and script information to BetaComment --- apps/openmw/mwscript/miscextensions.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index c7d221139..e8784f8de 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -964,6 +964,9 @@ namespace MWScript msg << "Grid: " << cell->getCell()->getGridX() << " " << cell->getCell()->getGridY() << std::endl; Ogre::Vector3 pos (ptr.getRefData().getPosition().pos); msg << "Coordinates: " << pos << std::endl; + msg << "Model: " << ptr.getClass().getModel(ptr) << std::endl; + if (!ptr.getClass().getScript(ptr).empty()) + msg << "Script: " << ptr.getClass().getScript(ptr) << std::endl; } std::string notes = runtime.getStringLiteral (runtime[0].mInteger); From 5f5fcc2feff49cce7933b6b5df79d8c856e015ae Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 28 Nov 2014 17:15:31 +0100 Subject: [PATCH 25/98] Make PlayGroup use an indefinite number of loops (Fixes #2156) --- apps/openmw/mwmechanics/character.cpp | 2 ++ apps/openmw/mwrender/animation.cpp | 11 +++++++++++ apps/openmw/mwrender/animation.hpp | 4 ++++ apps/openmw/mwscript/animationextensions.cpp | 2 +- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 72a9bbfde..11484ac49 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1645,6 +1645,8 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int } else if(mode == 0) { + if (!mAnimQueue.empty()) + mAnimation->stopLooping(mAnimQueue.front().first); mAnimQueue.resize(1); mAnimQueue.push_back(std::make_pair(groupname, count-1)); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 29db648d0..fc147ce59 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -842,6 +842,17 @@ void Animation::changeGroups(const std::string &groupname, int groups) return; } } + +void Animation::stopLooping(const std::string& groupname) +{ + AnimStateMap::iterator stateiter = mStates.find(groupname); + if(stateiter != mStates.end()) + { + stateiter->second.mLoopCount = 0; + return; + } +} + void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops) { if(!mSkelBase || mAnimSources.empty()) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 8ca3582dc..a8a9ee11e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -260,6 +260,10 @@ public: float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops); + /** If the given animation group is currently playing, set its remaining loop count to '0'. + */ + void stopLooping(const std::string& groupName); + /** Adjust the speed multiplier of an already playing animation. */ void adjustSpeedMult (const std::string& groupname, float speedmult); diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 52de8e042..613cf7d24 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -55,7 +55,7 @@ namespace MWScript throw std::runtime_error ("animation mode out of range"); } - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, 1); + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup (ptr, group, mode, std::numeric_limits::max()); } }; From ad38345de4aa9cf82e0042fafb93d63582429854 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 28 Nov 2014 22:23:42 +0100 Subject: [PATCH 26/98] Clean up listener in destruction of OgrePlatform (Fixes #2145) --- extern/shiny/Platforms/Ogre/OgrePlatform.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp index eab8f93e2..aa01c8ba1 100644 --- a/extern/shiny/Platforms/Ogre/OgrePlatform.cpp +++ b/extern/shiny/Platforms/Ogre/OgrePlatform.cpp @@ -54,6 +54,8 @@ namespace sh OgrePlatform::~OgrePlatform () { + Ogre::MaterialManager::getSingleton().removeListener(this); + delete sSerializer; } From 33c454e0734d0592eb46ae416c1e775185922dc8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 29 Nov 2014 20:39:25 +1100 Subject: [PATCH 27/98] Check whether any subrecords remain after skipping moved references. Should resolve bug #2070. --- components/esm/loadcell.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index bbd6696f1..f8966ad20 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -182,6 +182,13 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) // That should be it, I haven't seen any other fields yet. } + // If moved references are not handled then it is possible that CellRef::load() can lead + // to strange results because ESMReader::isNextSub("xxx") will always return false when + // there are no more subrecords. When moved references are handled properly by OpenCS + // below 2 lines can be removed. + if (!esm.hasMoreSubs()) + return false; + ref.load (esm); // Identify references belonging to a parent file and adapt the ID accordingly. From 5fa7536427d724c9ffbec43e29e56c44d6b5dad9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 29 Nov 2014 16:50:42 +0100 Subject: [PATCH 28/98] Fix incorrect box shape translation reset Fixes incorrect placement of collision box for "azura spirit_trib" --- components/nifbullet/bulletnifloader.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index b366216de..3abe0c171 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -133,8 +133,6 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mResourceName = mShape->getName(); mShape->mCollide = false; mBoundingBox = NULL; - mShape->mBoxTranslation = Ogre::Vector3(0,0,0); - mShape->mBoxRotation = Ogre::Quaternion::IDENTITY; mStaticMesh = NULL; mCompoundShape = NULL; From d3d5c1fd1546ae3d4731453c920d74d9fda2eabb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 29 Nov 2014 16:51:45 +0100 Subject: [PATCH 29/98] Disable debug drawing for raycasting shapes This reduces performance too much, and seeing both shapes overlaid on top of each other is confusing anyway. This can be reintroduced via a setting if necessary. --- libs/openengine/bullet/physic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index d7db81595..0b08e28d9 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -514,6 +514,7 @@ namespace Physic assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end()); mRaycastingObjectMap[name] = body; mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_Projectile); + body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); } return body; From 5ae1554a75cf1433e567355609346fedd1cb69fc Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 30 Nov 2014 04:00:06 +1100 Subject: [PATCH 30/98] Simplify skipping moved references (thanks scrawl) --- components/esm/loadcell.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index f8966ad20..347f3fde4 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -177,17 +177,10 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted) // 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")) { - esm.skipRecord(); // skip MVRF - esm.skipRecord(); // skip CNDT - // That should be it, I haven't seen any other fields yet. - } - - // If moved references are not handled then it is possible that CellRef::load() can lead - // to strange results because ESMReader::isNextSub("xxx") will always return false when - // there are no more subrecords. When moved references are handled properly by OpenCS - // below 2 lines can be removed. - if (!esm.hasMoreSubs()) + // skip rest of cell record (moved references), they are handled elsewhere + esm.skipRecord(); // skip MVRF, CNDT return false; + } ref.load (esm); From 4a9d2038fac8983b23b74b1c4a49914d218a0b4e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Nov 2014 14:33:39 +0100 Subject: [PATCH 31/98] load land for non-base content files immediately --- apps/opencs/model/world/data.cpp | 13 ++++++++++++- apps/opencs/model/world/idcollection.hpp | 18 +++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 9cb0299c4..87dbaa16d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -713,7 +713,18 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) case ESM::REC_PGRD: mPathgrids.load (*mReader, mBase); break; case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break; - case ESM::REC_LAND: mLand.load(*mReader, mBase); break; + + case ESM::REC_LAND: + { + int index = mLand.load(*mReader, mBase); + + if (index!=-1 && !mBase) + mLand.getRecord (index).mModified.mLand->loadData ( + ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | + ESM::Land::DATA_VTEX); + + break; + } case ESM::REC_CELL: { diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 0129ba3d8..f00ea447a 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -15,12 +15,15 @@ namespace CSMWorld public: - void load (ESM::ESMReader& reader, bool base); + /// \return Index of loaded record (-1 if no record was loaded) + int load (ESM::ESMReader& reader, bool base); /// \param index Index at which the record can be found. /// Special values: -2 index unknown, -1 record does not exist yet and therefore /// does not have an index - void load (const ESXRecordT& record, bool base, int index = -2); + /// + /// \return index + int load (const ESXRecordT& record, bool base, int index = -2); bool tryDelete (const std::string& id); ///< Try deleting \a id. If the id does not exist or can't be deleted the call is ignored. @@ -36,7 +39,7 @@ namespace CSMWorld } template - void IdCollection::load (ESM::ESMReader& reader, bool base) + int IdCollection::load (ESM::ESMReader& reader, bool base) { std::string id = reader.getHNOString ("NAME"); @@ -64,6 +67,8 @@ namespace CSMWorld record.mState = RecordBase::State_Deleted; this->setRecord (index, record); } + + return -1; } else { @@ -88,12 +93,12 @@ namespace CSMWorld index = newIndex; } - load (record, base, index); + return load (record, base, index); } } template - void IdCollection::load (const ESXRecordT& record, bool base, + int IdCollection::load (const ESXRecordT& record, bool base, int index) { if (index==-2) @@ -106,6 +111,7 @@ namespace CSMWorld record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; (base ? record2.mBase : record2.mModified) = record; + index = this->getSize(); this->appendRecord (record2); } else @@ -120,6 +126,8 @@ namespace CSMWorld this->setRecord (index, record2); } + + return index; } template From db17dbe3242938f3a1dc995c0924f4b4b149b59d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Nov 2014 18:04:18 +0100 Subject: [PATCH 32/98] don't store esm readers for non-base content files --- apps/opencs/model/world/data.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 87dbaa16d..737376f04 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -678,9 +678,15 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) if (!mReader->hasMoreRecs()) { - // Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading - boost::shared_ptr ptr(mReader); - mReaders.push_back(ptr); + if (mBase) + { + // Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading. + // We don't store non-base reader, because everything going into modified will be + // fully loaded during the initial loading process. + boost::shared_ptr ptr(mReader); + mReaders.push_back(ptr); + } + mReader = 0; mDialogue = 0; From 2720e5ea9df4aa2f8582bbb341792c24159218e7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Dec 2014 06:44:12 +1100 Subject: [PATCH 33/98] Remove PhysicsManager singleton and use shared_ptr instead. Resolves the issue where sometimes destructors were called in an unexpected sequence resulting in a crash while exiting the application. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/editor.cpp | 3 +- apps/opencs/editor.hpp | 2 - apps/opencs/model/doc/document.cpp | 12 +- apps/opencs/model/doc/document.hpp | 9 ++ apps/opencs/view/doc/view.cpp | 3 - apps/opencs/view/doc/viewmanager.cpp | 6 +- apps/opencs/view/render/cell.cpp | 2 +- apps/opencs/view/render/cell.hpp | 6 +- apps/opencs/view/render/mousestate.cpp | 2 +- apps/opencs/view/render/mousestate.hpp | 3 +- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/object.hpp | 7 +- .../view/render/pagedworldspacewidget.cpp | 2 +- .../view/render/unpagedworldspacewidget.cpp | 4 +- apps/opencs/view/render/worldspacewidget.cpp | 12 +- apps/opencs/view/render/worldspacewidget.hpp | 6 +- apps/opencs/view/world/physicsmanager.cpp | 110 ------------------ apps/opencs/view/world/physicsmanager.hpp | 54 --------- 19 files changed, 47 insertions(+), 200 deletions(-) delete mode 100644 apps/opencs/view/world/physicsmanager.cpp delete mode 100644 apps/opencs/view/world/physicsmanager.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 9d8dd89e1..bdfefbb83 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -68,7 +68,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem physicsmanager + scripthighlighter idvalidator dialoguecreator physicssystem ) opencs_units (view/widget diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index bef83b8ac..e756cb5df 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -21,7 +21,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) : mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), - mViewManager (mDocumentManager), mPhysicsManager (0), + mViewManager (mDocumentManager), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) { std::pair > config = readConfig(); @@ -34,7 +34,6 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); mOverlaySystem.reset (new CSVRender::OverlaySystem); - mPhysicsManager.reset (new CSVWorld::PhysicsManager); Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, mFsStrict); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index d55b0e873..cd39d53a4 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -28,7 +28,6 @@ #include "view/settings/dialog.hpp" #include "view/render/overlaysystem.hpp" -#include "view/world/physicsmanager.hpp" namespace OgreInit { @@ -45,7 +44,6 @@ namespace CS Files::ConfigurationManager mCfgMgr; CSMSettings::UserSettings mUserSettings; std::auto_ptr mOverlaySystem; - std::auto_ptr mPhysicsManager; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 4fdfd2e5e..4abd67a50 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -9,6 +9,8 @@ #include #endif +#include "../../view/world/physicssystem.hpp" + void CSMDoc::Document::addGmsts() { static const char *gmstFloats[] = @@ -2253,7 +2255,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), mSaving (*this, mProjectPath, encoding), - mRunner (mProjectPath) + mRunner (mProjectPath), mPhysics(boost::shared_ptr()) { if (mContentFiles.empty()) throw std::runtime_error ("Empty content file sequence"); @@ -2464,3 +2466,11 @@ void CSMDoc::Document::progress (int current, int max, int type) { emit progress (current, max, type, 1, this); } + +boost::shared_ptr CSMDoc::Document::getPhysics () +{ + if(!mPhysics) + mPhysics = boost::shared_ptr (new CSVWorld::PhysicsSystem()); + + return mPhysics; +} diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index c5f6d1006..e5aa5eea5 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -3,6 +3,7 @@ #include +#include #include #include @@ -39,6 +40,11 @@ namespace CSMWorld class ResourcesManager; } +namespace CSVWorld +{ + class PhysicsSystem; +} + namespace CSMDoc { class Document : public QObject @@ -57,6 +63,7 @@ namespace CSMDoc boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; + boost::shared_ptr mPhysics; // 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. @@ -129,6 +136,8 @@ namespace CSMDoc QTextDocument *getRunLog(); + boost::shared_ptr getPhysics(); + signals: void stateChanged (int state, CSMDoc::Document *document); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index d64d36aec..0d2b6060e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -16,7 +16,6 @@ #include "../../model/world/idtable.hpp" #include "../world/subviews.hpp" -#include "../world/physicsmanager.hpp" #include "../tools/subviews.hpp" @@ -407,8 +406,6 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory); connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); - - CSVWorld::PhysicsManager::instance()->setupPhysics(document); } CSVDoc::View::~View() diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index c4fd66884..55fd38c18 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include "../../model/doc/documentmanager.hpp" #include "../../model/doc/document.hpp" #include "../../model/world/columns.hpp" @@ -16,7 +18,6 @@ #include "../world/vartypedelegate.hpp" #include "../world/recordstatusdelegate.hpp" #include "../world/idtypedelegate.hpp" -#include "../world/physicsmanager.hpp" #include "../../model/settings/usersettings.hpp" @@ -219,7 +220,8 @@ void CSVDoc::ViewManager::removeDocAndView (CSMDoc::Document *document) mDocumentManager.removeDocument(document); (*iter)->deleteLater(); mViews.erase (iter); - CSVWorld::PhysicsManager::instance()->removeDocument(document); + // cleanup global resources used by OEngine + delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); updateIndices(); return; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 75e11cc10..1fb7809be 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -60,7 +60,7 @@ bool CSVRender::Cell::addObjects (int start, int end) } CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, CSVWorld::PhysicsSystem *physics, const Ogre::Vector3& origin) + const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index d38f0c68d..9f38b0d9f 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include @@ -38,7 +40,7 @@ namespace CSVRender Ogre::SceneNode *mCellNode; std::map mObjects; std::auto_ptr mTerrain; - CSVWorld::PhysicsSystem *mPhysics; + boost::shared_ptr mPhysics; Ogre::SceneManager *mSceneMgr; int mX; int mY; @@ -56,7 +58,7 @@ namespace CSVRender public: Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, - CSVWorld::PhysicsSystem *physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); + boost::shared_ptr physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); ~Cell(); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 45e846f74..988819fcb 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -56,7 +56,7 @@ namespace CSVRender // MouseState::MouseState(WorldspaceWidget *parent) - : mParent(parent), mPhysics(parent->getPhysics()), mSceneManager(parent->getSceneManager()) + : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(parent->getSceneManager()) , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index 27907bb33..70e18427f 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -2,6 +2,7 @@ #define OPENCS_VIEW_MOUSESTATE_H #include +#include #include #include @@ -43,7 +44,7 @@ namespace CSVRender MouseStates mMouseState; WorldspaceWidget *mParent; - CSVWorld::PhysicsSystem *mPhysics; // local copy + boost::shared_ptr mPhysics; Ogre::SceneManager *mSceneManager; // local copy QPoint mOldPos; diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 21219db8f..af3777d0c 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -132,7 +132,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const } CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, - const std::string& id, bool referenceable, CSVWorld::PhysicsSystem *physics, + const std::string& id, bool referenceable, boost::shared_ptr physics, bool forceBaseToZero) : mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics) { diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index eba2dc814..05a32fbea 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -1,6 +1,8 @@ #ifndef OPENCS_VIEW_OBJECT_H #define OPENCS_VIEW_OBJECT_H +#include + #include class QModelIndex; @@ -31,7 +33,7 @@ namespace CSVRender Ogre::SceneNode *mBase; NifOgre::ObjectScenePtr mObject; bool mForceBaseToZero; - CSVWorld::PhysicsSystem *mPhysics; + boost::shared_ptr mPhysics; /// Not implemented Object (const Object&); @@ -58,7 +60,8 @@ namespace CSVRender Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, const std::string& id, bool referenceable, - CSVWorld::PhysicsSystem *physics = NULL, bool forceBaseToZero = false); + boost::shared_ptr physics = boost::shared_ptr (), + bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place /// it at 0, 0, 0 instead. diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index e5d542858..bae0fcacf 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -111,7 +111,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() mCells.find (*iter)==mCells.end()) { Cell *cell = new Cell (mDocument.getData(), getSceneManager(), - iter->getId (mWorldspace), getPhysics()); + iter->getId (mWorldspace), mDocument.getPhysics()); mCells.insert (std::make_pair (*iter, cell)); float height = cell->getTerrainHeightAt(Ogre::Vector3( diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 07acbe493..3f8a45548 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -49,7 +49,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, getPhysics())); + mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics())); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +91,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getPhysics())); + mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics())); update(); emit cellChanged(*data.begin()); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 1f7c41512..9ea582f3d 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -16,7 +16,6 @@ #include "../widget/scenetooltoggle2.hpp" #include "../widget/scenetoolrun.hpp" -#include "../world/physicsmanager.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" @@ -56,9 +55,7 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - // associate WorldSpaceWidgets (and their SceneManagers) with Documents - // then create physics if there is a new document - mPhysics = CSVWorld::PhysicsManager::instance()->addSceneWidget(document, this); + mPhysics = document.getPhysics(); // create physics if one doesn't exist mPhysics->addSceneManager(getSceneManager(), this); mMouse = new MouseState(this); } @@ -67,7 +64,6 @@ CSVRender::WorldspaceWidget::~WorldspaceWidget () { delete mMouse; mPhysics->removeSceneManager(getSceneManager()); - CSVWorld::PhysicsManager::instance()->removeSceneWidget(this); } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) @@ -370,12 +366,6 @@ void CSVRender::WorldspaceWidget::updateOverlay() { } -CSVWorld::PhysicsSystem *CSVRender::WorldspaceWidget::getPhysics() -{ - assert(mPhysics); - return mPhysics; -} - void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { if(event->buttons() & Qt::RightButton) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 550b5d4a9..b19197e36 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -1,6 +1,8 @@ #ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H #define OPENCS_VIEW_WORLDSPACEWIDGET_H +#include + #include "scenewidget.hpp" #include "mousestate.hpp" @@ -40,7 +42,7 @@ namespace CSVRender CSVWidget::SceneToolToggle2 *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; - CSVWorld::PhysicsSystem *mPhysics; + boost::shared_ptr mPhysics; MouseState *mMouse; unsigned int mInteractionMask; @@ -115,8 +117,6 @@ namespace CSVRender virtual void updateOverlay(); - CSVWorld::PhysicsSystem *getPhysics(); - virtual void mouseMoveEvent (QMouseEvent *event); virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); diff --git a/apps/opencs/view/world/physicsmanager.cpp b/apps/opencs/view/world/physicsmanager.cpp deleted file mode 100644 index fa8db9e1e..000000000 --- a/apps/opencs/view/world/physicsmanager.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "physicsmanager.hpp" - -#include - -#include - -#include "../render/worldspacewidget.hpp" -#include "physicssystem.hpp" - -namespace CSVWorld -{ - PhysicsManager *PhysicsManager::mPhysicsManagerInstance = 0; - - PhysicsManager::PhysicsManager() - { - assert(!mPhysicsManagerInstance); - mPhysicsManagerInstance = this; - } - - PhysicsManager::~PhysicsManager() - { - std::map::iterator iter = mPhysics.begin(); - for(; iter != mPhysics.end(); ++iter) - delete iter->second; // shouldn't be any left but just in case - } - - PhysicsManager *PhysicsManager::instance() - { - assert(mPhysicsManagerInstance); - return mPhysicsManagerInstance; - } - - // create a physics instance per document, called from CSVDoc::View() to get Document* - void PhysicsManager::setupPhysics(CSMDoc::Document *doc) - { - std::map >::iterator iter = mSceneWidgets.find(doc); - if(iter == mSceneWidgets.end()) - { - mSceneWidgets[doc] = std::list (); // zero elements - mPhysics[doc] = new PhysicsSystem(); - } - } - - // destroy physics, called from CSVDoc::ViewManager - void PhysicsManager::removeDocument(CSMDoc::Document *doc) - { - std::map::iterator iter = mPhysics.find(doc); - if(iter != mPhysics.end()) - { - delete iter->second; - mPhysics.erase(iter); - } - - std::map >::iterator it = mSceneWidgets.find(doc); - if(it != mSceneWidgets.end()) - { - mSceneWidgets.erase(it); - } - - // cleanup global resources used by OEngine - if(mPhysics.empty()) - { - delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); - } - } - - // called from CSVRender::WorldspaceWidget() to get widgets' association with Document& - PhysicsSystem *PhysicsManager::addSceneWidget(CSMDoc::Document &doc, CSVRender::WorldspaceWidget *widget) - { - CSVRender::SceneWidget *sceneWidget = static_cast(widget); - - std::map >::iterator iter = mSceneWidgets.begin(); - for(; iter != mSceneWidgets.end(); ++iter) - { - if((*iter).first == &doc) - { - (*iter).second.push_back(sceneWidget); - return mPhysics[(*iter).first]; // TODO: consider using shared_ptr instead - } - } - - throw std::runtime_error("No physics system found for the given document."); - } - - // deprecated by removeDocument() and may be deleted in future code updates - // however there may be some value in removing the deleted scene widgets from the - // list so that the list does not grow forever - void PhysicsManager::removeSceneWidget(CSVRender::WorldspaceWidget *widget) - { - CSVRender::SceneWidget *sceneWidget = static_cast(widget); - - std::map >::iterator iter = mSceneWidgets.begin(); - for(; iter != mSceneWidgets.end(); ++iter) - { - std::list::iterator itWidget = (*iter).second.begin(); - for(; itWidget != (*iter).second.end(); ++itWidget) - { - if((*itWidget) == sceneWidget) - { - (*iter).second.erase(itWidget); - - //if((*iter).second.empty()) // last one for the document - // NOTE: do not delete physics until the document itself is closed - - break; - } - } - } - } -} diff --git a/apps/opencs/view/world/physicsmanager.hpp b/apps/opencs/view/world/physicsmanager.hpp deleted file mode 100644 index e17c9ac84..000000000 --- a/apps/opencs/view/world/physicsmanager.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef CSV_WORLD_PHYSICSMANAGER_H -#define CSV_WORLD_PHYSICSMANAGER_H - -#include -#include - -namespace Ogre -{ - class SceneManager; -} - -namespace CSMDoc -{ - class Document; -} - -namespace CSVRender -{ - class WorldspaceWidget; - class SceneWidget; -} - -namespace CSVWorld -{ - class PhysicsSystem; -} - -namespace CSVWorld -{ - class PhysicsManager - { - static PhysicsManager *mPhysicsManagerInstance; - - std::map > mSceneWidgets; - std::map mPhysics; - - public: - - PhysicsManager(); - ~PhysicsManager(); - - static PhysicsManager *instance(); - - void setupPhysics(CSMDoc::Document *); - - PhysicsSystem *addSceneWidget(CSMDoc::Document &doc, CSVRender::WorldspaceWidget *widget); - - void removeSceneWidget(CSVRender::WorldspaceWidget *widget); - - void removeDocument(CSMDoc::Document *doc); - }; -} - -#endif // CSV_WORLD_PHYSICSMANAGER_H From a4e32d23c6b6377a813a3029fa7fbfcd1eeb3a9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Nov 2014 20:52:34 +0100 Subject: [PATCH 34/98] Fix old profile content not being cleared correctly when saving content file selection (Fixes #2173) --- apps/launcher/datafilespage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 17951f2e4..f45b44470 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -137,6 +137,7 @@ void Launcher::DataFilesPage::saveSettings(const QString &profile) void Launcher::DataFilesPage::removeProfile(const QString &profile) { mLauncherSettings.remove(QString("Profiles/") + profile); + mLauncherSettings.remove(QString("Profiles/") + profile + QString("/content")); } QAbstractItemModel *Launcher::DataFilesPage::profilesModel() const From dffa8c6c149d1c90e9acde23a27d25d689fa38a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 30 Nov 2014 22:02:25 +0100 Subject: [PATCH 35/98] Re-insert existing DialInfo records when they are modified by another content file (Fixes #2170) --- components/esm/loaddial.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp index ff0362aa2..f2da8f377 100644 --- a/components/esm/loaddial.cpp +++ b/components/esm/loaddial.cpp @@ -63,6 +63,8 @@ void Dialogue::readInfo(ESMReader &esm, bool merge) std::map::iterator lookup; lookup = mLookup.find(id); + + ESM::DialInfo info; if (lookup != mLookup.end()) { it = lookup->second; @@ -70,13 +72,17 @@ void Dialogue::readInfo(ESMReader &esm, bool merge) // Merge with existing record. Only the subrecords that are present in // the new record will be overwritten. it->load(esm); - return; - } + info = *it; - // New record - ESM::DialInfo info; - info.mId = id; - info.load(esm); + // Since the record merging may have changed the next/prev linked list connection, we need to re-insert the record + mInfo.erase(it); + mLookup.erase(lookup); + } + else + { + info.mId = id; + info.load(esm); + } if (info.mNext.empty()) { From 9fb4b1f499689c77cdeb76c6021dfd2fb5fcb105 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Dec 2014 08:15:17 +1100 Subject: [PATCH 36/98] Initialise null shared_ptr --- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 9ea582f3d..879200b5d 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -22,7 +22,7 @@ #include "editmode.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mPhysics(0), mMouse(0), +: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mPhysics(boost::shared_ptr()), mMouse(0), mInteractionMask (0) { setAcceptDrops(true); From 2d229c70cb163637c0057f67021a01eab8b872ad Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Dec 2014 09:41:03 +1100 Subject: [PATCH 37/98] Another missed null shared_ptr conversion for gcc. --- apps/opencs/view/render/previewwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index f972c6361..da18e7c89 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -10,7 +10,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) : SceneWidget (parent), mData (data), - mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, NULL, true) + mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, boost::shared_ptr(), true) { setNavigation (&mOrbit); From 44b11163d18dd43b7e8bc3e1203049373480476f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Dec 2014 10:07:02 +1100 Subject: [PATCH 38/98] Do not delete physics objects if it was never created (e.g. preview window) --- apps/opencs/view/render/object.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index af3777d0c..d92b4aaa2 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -156,7 +156,8 @@ CSVRender::Object::~Object() { clear(); - mPhysics->removeObject(mBase->getName()); + if(mPhysics) // preview may not have physics enabled + mPhysics->removeObject(mBase->getName()); if (mBase) mBase->getCreator()->destroySceneNode (mBase); From 64e1594b4179688e79a5fa01193239af73c9174a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Dec 2014 14:08:27 +1100 Subject: [PATCH 39/98] Move the destruction of global resources, being used by multiple documents, to the editor. --- apps/opencs/editor.cpp | 7 ++++++- apps/opencs/view/doc/viewmanager.cpp | 4 ---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e756cb5df..53c6865eb 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -1,6 +1,8 @@ #include "editor.hpp" +#include + #include #include #include @@ -69,7 +71,10 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) } CS::Editor::~Editor () -{} +{ + // cleanup global resources used by OEngine + delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); +} void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) { diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 55fd38c18..5f6b6b46a 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include "../../model/doc/documentmanager.hpp" #include "../../model/doc/document.hpp" #include "../../model/world/columns.hpp" @@ -220,8 +218,6 @@ void CSVDoc::ViewManager::removeDocAndView (CSMDoc::Document *document) mDocumentManager.removeDocument(document); (*iter)->deleteLater(); mViews.erase (iter); - // cleanup global resources used by OEngine - delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); updateIndices(); return; From 3b5cd286f6ee51b50baf136040f4033ad589ad81 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 1 Dec 2014 14:09:22 +1100 Subject: [PATCH 40/98] Do not destroy overlay if it was never created (e.g. due to an Ogre exception). --- apps/opencs/view/render/pagedworldspacewidget.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index bae0fcacf..e7954491f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -362,8 +362,11 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() delete iter->second; } - removeRenderTargetListener(mOverlayMask); - delete mOverlayMask; + if(mOverlayMask) + { + removeRenderTargetListener(mOverlayMask); + delete mOverlayMask; + } } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) From 6e1a11f3220761c5ac808019d78eb69c4560ec67 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 1 Dec 2014 19:13:04 +0100 Subject: [PATCH 41/98] Queue screen fade operations invoked by scripts --- apps/openmw/mwbase/windowmanager.hpp | 6 +++--- apps/openmw/mwgui/windowmanagerimp.cpp | 15 +++++++++------ apps/openmw/mwgui/windowmanagerimp.hpp | 6 +++--- apps/openmw/mwscript/miscextensions.cpp | 6 +++--- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index bfc4f3b33..d4f1afa32 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -330,11 +330,11 @@ namespace MWBase virtual void pinWindow (MWGui::GuiWindow window) = 0; /// Fade the screen in, over \a time seconds - virtual void fadeScreenIn(const float time) = 0; + virtual void fadeScreenIn(const float time, bool clearQueue=true) = 0; /// Fade the screen out to black, over \a time seconds - virtual void fadeScreenOut(const float time) = 0; + virtual void fadeScreenOut(const float time, bool clearQueue=true) = 0; /// Fade the screen to a specified percentage of black, over \a time seconds - virtual void fadeScreenTo(const int percent, const float time) = 0; + virtual void fadeScreenTo(const int percent, const float time, bool clearQueue=true) = 0; /// Darken the screen to a specified percentage virtual void setBlindness(const int percent) = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6ab8b94c5..48f28d300 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1748,21 +1748,24 @@ namespace MWGui updateVisible(); } - void WindowManager::fadeScreenIn(const float time) + void WindowManager::fadeScreenIn(const float time, bool clearQueue) { - mScreenFader->clearQueue(); + if (clearQueue) + mScreenFader->clearQueue(); mScreenFader->fadeOut(time); } - void WindowManager::fadeScreenOut(const float time) + void WindowManager::fadeScreenOut(const float time, bool clearQueue) { - mScreenFader->clearQueue(); + if (clearQueue) + mScreenFader->clearQueue(); mScreenFader->fadeIn(time); } - void WindowManager::fadeScreenTo(const int percent, const float time) + void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue) { - mScreenFader->clearQueue(); + if (clearQueue) + mScreenFader->clearQueue(); mScreenFader->fadeTo(percent, time); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index aa5bd0fc9..94d8a93db 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -325,11 +325,11 @@ namespace MWGui virtual void pinWindow (MWGui::GuiWindow window); /// Fade the screen in, over \a time seconds - virtual void fadeScreenIn(const float time); + virtual void fadeScreenIn(const float time, bool clearQueue); /// Fade the screen out to black, over \a time seconds - virtual void fadeScreenOut(const float time); + virtual void fadeScreenOut(const float time, bool clearQueue); /// Fade the screen to a specified percentage of black, over \a time seconds - virtual void fadeScreenTo(const int percent, const float time); + virtual void fadeScreenTo(const int percent, const float time, bool clearQueue); /// Darken the screen to a specified percentage virtual void setBlindness(const int percent); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index e8784f8de..aa80213de 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -246,7 +246,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWindowManager()->fadeScreenIn(time); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(time, false); } }; @@ -259,7 +259,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWindowManager()->fadeScreenOut(time); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(time, false); } }; @@ -275,7 +275,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWindowManager()->fadeScreenTo(alpha, time); + MWBase::Environment::get().getWindowManager()->fadeScreenTo(alpha, time, false); } }; From 48d5789aeb94c5916395b16929438350146ba09f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 22:10:06 +0100 Subject: [PATCH 42/98] Use a separate flag for references deleted by a content file (Fixes #2018) The flag must be separate so as to not contaminate the user's savegame. Fixes the following use cases that were broken before: - Content file edits a reference that was already deleted by a previously loaded content file -> reference must stay deleted - Changed or new content file deletes a reference that is already present in the user's savegame -> reference must be deleted - Said content file is disabled again - reference must be undeleted --- apps/openmw/mwworld/cellstore.cpp | 2 +- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/localscripts.cpp | 2 +- apps/openmw/mwworld/refdata.cpp | 19 ++++++++++++++++--- apps/openmw/mwworld/refdata.hpp | 11 ++++++++++- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 7 files changed, 31 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index ce8d77758..52e70fef2 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -156,7 +156,7 @@ namespace MWWorld LiveRef liveCellRef (ref, ptr); if (deleted) - liveCellRef.mData.setCount (0); + liveCellRef.mData.setDeleted(true); if (iter != mList.end()) *iter = liveCellRef; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index e322ef4a4..05e7b0b2e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -196,7 +196,7 @@ namespace MWWorld for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { - if (!iter->mData.getCount()) + if (iter->mData.isDeleted()) continue; if (!functor (MWWorld::Ptr(&*iter, this))) return false; diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index f3a647124..d74aab694 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -17,7 +17,7 @@ namespace cellRefList.mList.begin()); iter!=cellRefList.mList.end(); ++iter) { - if (!iter->mBase->mScript.empty() && iter->mData.getCount()) + if (!iter->mBase->mScript.empty() && !iter->mData.isDeleted()) { localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell)); } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index f4bc64b70..78fea2b86 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -23,6 +23,7 @@ namespace MWWorld mPosition = refData.mPosition; mLocalRotation = refData.mLocalRotation; mChanged = refData.mChanged; + mDeleted = refData.mDeleted; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -36,7 +37,7 @@ namespace MWWorld } RefData::RefData() - : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false) + : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false), mDeleted(false) { for (int i=0; i<3; ++i) { @@ -49,7 +50,8 @@ namespace MWWorld RefData::RefData (const ESM::CellRef& cellRef) : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0), - mChanged(false) // Loading from ESM/ESP files -> assume unchanged + mChanged(false), // Loading from ESM/ESP files -> assume unchanged + mDeleted(false) { mLocalRotation.rot[0]=0; mLocalRotation.rot[1]=0; @@ -59,7 +61,8 @@ namespace MWWorld RefData::RefData (const ESM::ObjectState& objectState) : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), - mChanged(true) // Loading from a savegame -> assume changed + mChanged(true), // Loading from a savegame -> assume changed + mDeleted(false) { for (int i=0; i<3; ++i) mLocalRotation.rot[i] = objectState.mLocalRotation[i]; @@ -167,6 +170,16 @@ namespace MWWorld mCount = count; } + void RefData::setDeleted(bool deleted) + { + mDeleted = deleted; + } + + bool RefData::isDeleted() const + { + return mDeleted || mCount == 0; + } + MWScript::Locals& RefData::getLocals() { return mLocals; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index db66c091b..1ed3cd79d 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -37,6 +37,8 @@ namespace MWWorld bool mEnabled; int mCount; // 0: deleted + bool mDeleted; // separate delete flag used for deletion by a content file + ESM::Position mPosition; LocalRotation mLocalRotation; @@ -86,12 +88,19 @@ namespace MWWorld void setLocals (const ESM::Script& script); void setCount (int count); - /// Set object count (an object pile is a simple object with a count >1). + ///< Set object count (an object pile is a simple object with a count >1). /// /// \warning Do not call setCount() to add or remove objects from a /// container or an actor's inventory. Call ContainerStore::add() or /// ContainerStore::remove() instead. + /// This flag is only used for content stack loading and will not be stored in the savegame. + /// If the object was deleted by gameplay, then use setCount(0) instead. + void setDeleted(bool deleted); + + /// Returns true if the object was either deleted by the content file or by gameplay. + bool isDeleted() const; + MWScript::Locals& getLocals(); bool isEnabled() const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 6f18a6ef3..02c9db9ea 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -75,7 +75,7 @@ namespace ptr.getCellRef().setScale(2); } - if (ptr.getRefData().getCount() && ptr.getRefData().isEnabled()) + if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled()) { try { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4c2bd669b..7baf1d3e5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1057,7 +1057,7 @@ namespace MWWorld void World::deleteObject (const Ptr& ptr) { - if (ptr.getRefData().getCount() > 0) + if (!ptr.getRefData().isDeleted()) { ptr.getRefData().setCount(0); From cbcd6a26d568d6a4b161fc2f849cba701bc4bef1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 1 Dec 2014 22:57:32 +0100 Subject: [PATCH 43/98] memory leak fix --- apps/opencs/model/world/data.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 737376f04..f6bd8e13b 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -686,6 +686,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) boost::shared_ptr ptr(mReader); mReaders.push_back(ptr); } + else + delete mReader; mReader = 0; From 61d1aa78ce94c60414b31e1ac88614f35ebf8748 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 13:34:42 +0100 Subject: [PATCH 44/98] Move AiWander path finder to temporary storage (Fixes #2082) --- apps/openmw/mwmechanics/aipackage.hpp | 1 + apps/openmw/mwmechanics/aiwander.cpp | 44 ++++++++++++++------------- apps/openmw/mwmechanics/aiwander.hpp | 5 +-- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index df970f801..f1c9ec7d2 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -69,6 +69,7 @@ namespace MWMechanics /** \return If the actor has arrived at his destination **/ bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration); + // TODO: all this does not belong here, move into temporary storage PathFinder mPathFinder; ObstacleCheck mObstacleCheck; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a70200833..a5be250f7 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -57,6 +57,8 @@ namespace MWMechanics bool mWalking; unsigned short mPlayedIdle; + + PathFinder mPathFinder; AiWanderStorage(): mTargetAngle(0), @@ -211,9 +213,9 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) { - stopWalking(actor); + stopWalking(actor, storage); moveNow = false; walking = false; chooseAction = true; @@ -225,7 +227,7 @@ namespace MWMechanics if(walking) // have not yet reached the destination { // turn towards the next point in mPath - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); + zTurn(actor, Ogre::Degree(storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); actor.getClass().getMovementSettings(actor).mPosition[1] = 1; // Returns true if evasive action needs to be taken @@ -236,9 +238,9 @@ namespace MWMechanics { // remove allowed points then select another random destination mTrimCurrentNode = true; - trimAllowedNodes(mAllowedNodes, mPathFinder); + trimAllowedNodes(mAllowedNodes, storage.mPathFinder); mObstacleCheck.clear(); - mPathFinder.clearPath(); + storage.mPathFinder.clearPath(); walking = false; moveNow = true; } @@ -249,7 +251,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too - zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); + zTurn(actor, Ogre::Degree(storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); } mStuckCount++; // TODO: maybe no longer needed } @@ -260,7 +262,7 @@ namespace MWMechanics //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; mObstacleCheck.clear(); - stopWalking(actor); + stopWalking(actor, storage); moveNow = false; walking = false; chooseAction = true; @@ -300,7 +302,7 @@ namespace MWMechanics { if(!mRepeat) { - stopWalking(actor); + stopWalking(actor, storage); return true; } else @@ -310,7 +312,7 @@ namespace MWMechanics { if(!mRepeat) { - stopWalking(actor); + stopWalking(actor, storage); return true; } else @@ -411,7 +413,7 @@ namespace MWMechanics chooseAction = false; idleNow = false; - if (!mPathFinder.isPathConstructed()) + if (!storage.mPathFinder.isPathConstructed()) { Ogre::Vector3 destNodePos = mReturnPosition; @@ -427,9 +429,9 @@ namespace MWMechanics start.mZ = pos.pos[2]; // don't take shortcuts for wandering - mPathFinder.buildPath(start, dest, actor.getCell(), false); + storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); - if(mPathFinder.isPathConstructed()) + if(storage.mPathFinder.isPathConstructed()) { moveNow = false; walking = true; @@ -517,7 +519,7 @@ namespace MWMechanics if(walking) { - stopWalking(actor); + stopWalking(actor, storage); moveNow = false; walking = false; mObstacleCheck.clear(); @@ -567,7 +569,7 @@ namespace MWMechanics if(moveNow && mDistance) { // Construct a new path if there isn't one - if(!mPathFinder.isPathConstructed()) + if(!storage.mPathFinder.isPathConstructed()) { assert(mAllowedNodes.size()); unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); @@ -589,16 +591,16 @@ namespace MWMechanics start.mZ = pos.pos[2]; // don't take shortcuts for wandering - mPathFinder.buildPath(start, dest, actor.getCell(), false); + storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); - if(mPathFinder.isPathConstructed()) + if(storage.mPathFinder.isPathConstructed()) { // buildPath inserts dest in case it is not a pathgraph point // index which is a duplicate for AiWander. However below code // does not work since getPath() returns a copy of path not a // reference - //if(mPathFinder.getPathSize() > 1) - //mPathFinder.getPath().pop_back(); + //if(storage.mPathFinder.getPathSize() > 1) + //storage.mPathFinder.getPath().pop_back(); // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; @@ -616,7 +618,7 @@ namespace MWMechanics // Choose a different node and delete this one from possible nodes because it is uncreachable: else mAllowedNodes.erase(mAllowedNodes.begin() + randNode); - } + } } return false; // AiWander package not yet completed @@ -653,9 +655,9 @@ namespace MWMechanics return TypeIdWander; } - void AiWander::stopWalking(const MWWorld::Ptr& actor) + void AiWander::stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage) { - mPathFinder.clearPath(); + storage.mPathFinder.clearPath(); actor.getClass().getMovementSettings(actor).mPosition[1] = 0; } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 0600909ba..b9b394a26 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -27,6 +27,8 @@ namespace MWMechanics { + struct AiWanderStorage; + /// \brief Causes the Actor to wander within a specified range class AiWander : public AiPackage { @@ -65,7 +67,7 @@ namespace MWMechanics // NOTE: mDistance and mDuration must be set already void init(); - void stopWalking(const MWWorld::Ptr& actor); + void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); void getRandomIdle(unsigned short& playedIdle); @@ -101,7 +103,6 @@ namespace MWMechanics void trimAllowedNodes(std::vector& nodes, const PathFinder& pathfinder); -// PathFinder mPathFinder; // ObstacleCheck mObstacleCheck; float mDoorCheckDuration; From 6960cac5eb279562c7791a92e3b7bb9af93a00f3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 13:38:47 +0100 Subject: [PATCH 45/98] Disable third person zoom feature by default due to usability issues (Fixes #2129) --- apps/openmw/mwinput/inputmanagerimp.cpp | 4 +++- files/settings-default.cfg | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 68682abea..48acd22ba 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -623,7 +623,9 @@ namespace MWInput if (arg.zrel && mControlSwitch["playerviewswitch"] && mControlSwitch["playercontrols"]) //Check to make sure you are allowed to zoomout and there is a change { MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.zrel); - MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); + + if (Settings::Manager::getBool("allow third person zoom", "Input")) + MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); } } } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 12b52d3db..7566994e2 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -179,6 +179,8 @@ camera y multiplier = 1.0 always run = false +allow third person zoom = false + [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false From c684c99a95f3462ee96926af8a8eafbbf3b39975 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 13:43:11 +0100 Subject: [PATCH 46/98] Combat AI: Don't attempt to cast spells when impossible to succeed (Fixes #2059) --- apps/openmw/mwmechanics/aicombataction.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index cc8279b1e..6b4ede305 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -9,6 +9,7 @@ #include "../mwworld/actionequip.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/spellcasting.hpp" #include #include @@ -166,6 +167,9 @@ namespace MWMechanics { const CreatureStats& stats = actor.getClass().getCreatureStats(actor); + if (MWMechanics::getSpellSuccessChance(spell, actor) == 0) + return 0.f; + if (spell->mData.mType != ESM::Spell::ST_Spell) return 0.f; From 077c619611ace83df33ced9066931d8086b55f89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 14:36:36 +0100 Subject: [PATCH 47/98] Implement Clamp mode for NiTexturingProperty (Fixes #2050) --- components/nifogre/material.cpp | 30 ++++++++++++++++++++++++++---- files/materials/objects.mat | 4 ++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp index 517f29f4e..04eb86ba6 100644 --- a/components/nifogre/material.cpp +++ b/components/nifogre/material.cpp @@ -54,6 +54,28 @@ static const char *getTestMode(int mode) return "less_equal"; } +static void setTextureProperties(sh::MaterialInstance* material, const std::string& textureSlotName, const Nif::NiTexturingProperty::Texture& tex) +{ + material->setProperty(textureSlotName + "UVSet", sh::makeProperty(new sh::IntValue(tex.uvSet))); + const std::string clampMode = textureSlotName + "ClampMode"; + switch (tex.clamp) + { + case 0: + material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("clamp clamp"))); + break; + case 1: + material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("clamp wrap"))); + break; + case 2: + material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("wrap clamp"))); + break; + case 3: + default: + material->setProperty(clampMode, sh::makeProperty(new sh::StringValue("wrap wrap"))); + break; + } +} + Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, @@ -294,22 +316,22 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, if (!texName[Nif::NiTexturingProperty::BaseTexture].empty()) { instance->setProperty("use_diffuse_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("diffuseMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::BaseTexture].uvSet))); + setTextureProperties(instance, "diffuseMap", texprop->textures[Nif::NiTexturingProperty::BaseTexture]); } if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) { instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); + setTextureProperties(instance, "emissiveMap", texprop->textures[Nif::NiTexturingProperty::GlowTexture]); } if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) { instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); + setTextureProperties(instance, "detailMap", texprop->textures[Nif::NiTexturingProperty::DetailTexture]); } if (!texName[Nif::NiTexturingProperty::DarkTexture].empty()) { instance->setProperty("use_dark_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("darkMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DarkTexture].uvSet))); + setTextureProperties(instance, "darkMap", texprop->textures[Nif::NiTexturingProperty::DarkTexture]); } bool useParallax = !texName[Nif::NiTexturingProperty::BumpTexture].empty() diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 932c7e25f..149160760 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -73,6 +73,7 @@ material openmw_objects_base direct_texture $diffuseMap create_in_ffp $use_diffuse_map tex_coord_set $diffuseMapUVSet + tex_address_mode $diffuseMapClampMode } texture_unit normalMap @@ -89,6 +90,7 @@ material openmw_objects_base alpha_op_ex modulate src_current src_texture direct_texture $darkMap tex_coord_set $darkMapUVSet + tex_address_mode $darkMapClampMode } texture_unit detailMap @@ -97,6 +99,7 @@ material openmw_objects_base colour_op_ex modulate_x2 src_current src_texture direct_texture $detailMap tex_coord_set $detailMapUVSet + tex_address_mode $detailMapClampMode } texture_unit emissiveMap @@ -105,6 +108,7 @@ material openmw_objects_base colour_op add direct_texture $emissiveMap tex_coord_set $emissiveMapUVSet + tex_address_mode $emissiveMapClampMode } texture_unit envMap From 59cde9b4314234b22d8b24f8993035692b8222bf Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 14:38:50 +0100 Subject: [PATCH 48/98] Don't use transparency override if there's no transparency (rug fix for Bug #2050) --- components/nifogre/material.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp index 04eb86ba6..072f16344 100644 --- a/components/nifogre/material.cpp +++ b/components/nifogre/material.cpp @@ -354,7 +354,7 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Override alpha flags based on our override list (transparency-overrides.cfg) - if (!texName[0].empty()) + if ((alphaFlags&1) && !texName[0].empty()) { NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); if (result.first) From 8103d25b09710f1d4fa7d7bec727d0bec60ece93 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 14:48:53 +0100 Subject: [PATCH 49/98] Make ToggleMenus close open windows (Fixes #2045) --- apps/openmw/mwscript/guiextensions.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index afc745beb..1d34adbca 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -210,6 +210,12 @@ namespace MWScript { bool state = MWBase::Environment::get().getWindowManager()->toggleGui(); runtime.getContext().report(state ? "GUI -> On" : "GUI -> Off"); + + if (!state) + { + while (MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_None) // don't use isGuiMode, or we get an infinite loop for modal message boxes! + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } } }; From f9ae0d9d665b7ad08327017e417cc4572b0b48d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 14:56:13 +0100 Subject: [PATCH 50/98] Fix dialogue goodbye link conflicting with choice links --- apps/openmw/mwgui/dialogue.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 6526b200f..eb548d596 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -533,9 +533,11 @@ namespace MWGui if (mGoodbye) { + Goodbye* link = new Goodbye(); + mLinks.push_back(link); std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString(); BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, linkNormal, linkHot, linkActive, - TypesetBook::InteractiveId(mLinks.back())); + TypesetBook::InteractiveId(link)); typesetter->lineBreak(); typesetter->write(questionStyle, to_utf8_span(goodbye.c_str())); } @@ -654,7 +656,6 @@ namespace MWGui void DialogueWindow::goodbye() { - mLinks.push_back(new Goodbye()); mGoodbye = true; mEnabled = false; updateHistory(); From a1226501fac2f1f25213ffad546d2565fede51fd Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 15:08:55 +0100 Subject: [PATCH 51/98] AiWander: move idle animation handling to non-delayed section (Fixes #2073) --- apps/openmw/mwmechanics/aiwander.cpp | 105 ++++++++++++++------------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index a5be250f7..c8a0c85d5 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -282,6 +282,58 @@ namespace MWMechanics rotate = false; } + // Check if idle animation finished + short unsigned& playedIdle = storage.mPlayedIdle; + GreetingState& greetingState = storage.mSaidGreeting; + if(idleNow && !checkIdle(actor, playedIdle) && (greetingState == Greet_Done || greetingState == Greet_None)) + { + playedIdle = 0; + idleNow = false; + chooseAction = true; + } + + MWBase::World *world = MWBase::Environment::get().getWorld(); + + if(chooseAction) + { + playedIdle = 0; + getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection + + if(!playedIdle && mDistance) + { + chooseAction = false; + moveNow = true; + } + else + { + // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + MWWorld::TimeStamp currentTime = world->getTimeStamp(); + mStartTime = currentTime; + playIdle(actor, playedIdle); + chooseAction = false; + idleNow = true; + + // Play idle voiced dialogue entries randomly + int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); + if (hello > 0) + { + int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + + // Don't bother if the player is out of hearing range + static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() + .get().find("fVoiceIdleOdds")->getFloat(); + + // Only say Idle voices when player is in LOS + // A bit counterintuitive, likely vanilla did this to reduce the appearance of + // voices going through walls? + if (roll < fVoiceIdleOdds && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500 + && MWBase::Environment::get().getWorld()->getLOS(player, actor)) + MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); + } + } + } + float& lastReaction = storage.mReaction; lastReaction += duration; if(lastReaction < REACTION_INTERVAL) @@ -293,7 +345,6 @@ namespace MWMechanics // NOTE: everything below get updated every REACTION_INTERVAL seconds - MWBase::World *world = MWBase::Environment::get().getWorld(); if(mDuration) { // End package if duration is complete or mid-night hits: @@ -439,48 +490,6 @@ namespace MWMechanics } } - AiWander::GreetingState& greetingState = storage.mSaidGreeting; - short unsigned& playedIdle = storage.mPlayedIdle; - if(chooseAction) - { - playedIdle = 0; - getRandomIdle(playedIdle); // NOTE: sets mPlayedIdle with a random selection - - if(!playedIdle && mDistance) - { - chooseAction = false; - moveNow = true; - } - else - { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); - mStartTime = currentTime; - playIdle(actor, playedIdle); - chooseAction = false; - idleNow = true; - - // Play idle voiced dialogue entries randomly - int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - if (hello > 0) - { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - - // Don't bother if the player is out of hearing range - static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() - .get().find("fVoiceIdleOdds")->getFloat(); - - // Only say Idle voices when player is in LOS - // A bit counterintuitive, likely vanilla did this to reduce the appearance of - // voices going through walls? - if (roll < fVoiceIdleOdds && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500 - && MWBase::Environment::get().getWorld()->getLOS(player, actor)) - MWBase::Environment::get().getDialogueManager()->say(actor, "idle"); - } - } - } - // Allow interrupting a walking actor to trigger a greeting if(idleNow || walking) { @@ -496,7 +505,7 @@ namespace MWMechanics Ogre::Vector3 playerPos(player.getRefData().getPosition().pos); Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); float playerDistSqr = playerPos.squaredDistance(actorPos); - + int& greetingTimer = storage.mGreetingTimer; if (greetingState == Greet_None) { @@ -556,14 +565,6 @@ namespace MWMechanics if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset) greetingState = Greet_None; } - - // Check if idle animation finished - if(!checkIdle(actor, playedIdle) && (playerDistSqr > helloDistance*helloDistance || greetingState == MWMechanics::AiWander::Greet_Done)) - { - playedIdle = 0; - idleNow = false; - chooseAction = true; - } } if(moveNow && mDistance) From ed686ddd2f403dccd713aaa8c97aded49aca1631 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 15:37:34 +0100 Subject: [PATCH 52/98] Don't update nodes with an empty name from the skeleton source (Fixes #2125) --- apps/openmw/mwrender/animation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fc147ce59..548906cdf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -574,7 +574,8 @@ float Animation::getVelocity(const std::string &groupname) const static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) { - if(skelsrc->hasBone(bone->getName())) + if(bone->getName() != " " // really should be != "", but see workaround in skeleton.cpp for empty node names + && skelsrc->hasBone(bone->getName())) { Ogre::Bone *srcbone = skelsrc->getBone(bone->getName()); if(!srcbone->getParent() || !bone->getParent()) From 507cbcfae320a02e7b2af2651faac4571f09b5e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 16:04:00 +0100 Subject: [PATCH 53/98] Remove incorrect implementation of the iAlarm* GMSTs, not used by vanilla MW (Fixes #2064) According to Hrnchamd, these are unused. The real mechanics are not fully documented, but from a quick test only NPCs with an alarm value of 100 will report crimes. --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index f7949f1ec..b24232747 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -930,19 +930,6 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - // What amount of alarm did this crime generate? - int alarm = 0; - if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) - alarm = esmStore.get().find("iAlarmTresspass")->getInt(); - else if (type == OT_Pickpocket) - alarm = esmStore.get().find("iAlarmPickPocket")->getInt(); - else if (type == OT_Assault) - alarm = esmStore.get().find("iAlarmAttack")->getInt(); - else if (type == OT_Murder) - alarm = esmStore.get().find("iAlarmKilling")->getInt(); - else if (type == OT_Theft) - alarm = esmStore.get().find("iAlarmStealing")->getInt(); - bool reported = false; // Find all the actors within the alarm radius @@ -988,7 +975,7 @@ namespace MWMechanics continue; // Will the witness report the crime? - if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) + if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100) { reported = true; } From 46d93f1b08984c234a090a4207f40e8480c4147a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 16:36:01 +0100 Subject: [PATCH 54/98] Crime update: NPCs can report crimes if they didn't see the crime, but were alerted by someone who saw it and did not report it themselves. --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b24232747..b4edf44aa 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -930,7 +930,6 @@ namespace MWMechanics const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); - bool reported = false; // Find all the actors within the alarm radius std::vector neighbors; @@ -947,6 +946,8 @@ namespace MWMechanics bool victimAware = false; // Find actors who directly witnessed the crime + bool crimeSeen = false; + bool reported = false; for (std::vector::iterator it = neighbors.begin(); it != neighbors.end(); ++it) { if (*it == player) @@ -974,15 +975,17 @@ namespace MWMechanics if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) continue; - // Will the witness report the crime? - if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100) - { - reported = true; - } + crimeSeen = true; + } + + // Will the witness report the crime? + if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= 100) + { + reported = true; } } - if (reported) + if (crimeSeen && reported) reportCrime(player, victim, type, arg); else if (victimAware && !victim.isEmpty() && type == OT_Assault) startCombat(victim, player); From b9d0552166c7ad283b166d38731aaf5b1875c64e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 16:43:55 +0100 Subject: [PATCH 55/98] Fix positionCell rotation argument when used on the player This fixes the player's initial orientation on the starting boat, to properly face Jiub. --- .../mwscript/transformationextensions.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index e74388eff..8e6d925b7 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -319,12 +319,11 @@ namespace MWScript ptr = MWWorld::Ptr(ptr.getBase(), store); float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); - if(ptr.getTypeName() == typeid(ESM::NPC).name())//some morrowind oddity - { - ax = ax/60.; - ay = ay/60.; + // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) + // except for when you position the player, then degrees must be used. + // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. + if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) zRot = zRot/60.; - } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); @@ -378,12 +377,11 @@ namespace MWScript float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); - if(ptr.getTypeName() == typeid(ESM::NPC).name())//some morrowind oddity - { - ax = ax/60.; - ay = ay/60.; + // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) + // except for when you position the player, then degrees must be used. + // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. + if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) zRot = zRot/60.; - } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); } From fadbb5ad2196418c558abf977b3f2db0ed87489e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 20:31:33 +0100 Subject: [PATCH 56/98] Add particle and sound fading for weather transitions (Fixes #2130) --- apps/openmw/mwrender/sky.cpp | 40 ++++++++++++++++ apps/openmw/mwworld/weather.cpp | 82 ++++++++++++++++++--------------- apps/openmw/mwworld/weather.hpp | 16 ++++--- 3 files changed, 94 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index ccef74efb..184102127 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -34,6 +34,41 @@ using namespace MWRender; using namespace Ogre; +namespace +{ + +void setAlpha (NifOgre::ObjectScenePtr scene, Ogre::MovableObject* movable, float alpha) +{ + Ogre::MaterialPtr mat = scene->mMaterialControllerMgr.getWritableMaterial(movable); + Ogre::Material::TechniqueIterator techs = mat->getTechniqueIterator(); + while(techs.hasMoreElements()) + { + Ogre::Technique *tech = techs.getNext(); + Ogre::Technique::PassIterator passes = tech->getPassIterator(); + while(passes.hasMoreElements()) + { + Ogre::Pass *pass = passes.getNext(); + Ogre::ColourValue diffuse = pass->getDiffuse(); + diffuse.a = alpha; + pass->setDiffuse(diffuse); + } + } + +} + +void setAlpha (NifOgre::ObjectScenePtr scene, float alpha) +{ + for(size_t i = 0; i < scene->mParticles.size(); ++i) + setAlpha(scene, scene->mParticles[i], alpha); + for(size_t i = 0; i < scene->mEntities.size(); ++i) + { + if (scene->mEntities[i] != scene->mSkelBase) + setAlpha(scene, scene->mEntities[i], alpha); + } +} + +} + BillboardObject::BillboardObject( const String& textureName, const float initialSize, const Vector3& position, @@ -660,6 +695,11 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) mSun->setVisibility(weather.mGlareView * strength); mAtmosphereNight->setVisible(weather.mNight && mEnabled); + + if (mParticle.get()) + setAlpha(mParticle, weather.mEffectFade); + for (std::map::iterator it = mRainModels.begin(); it != mRainModels.end(); ++it) + setAlpha(it->second, weather.mEffectFade); } void SkyManager::setGlare(const float glare) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index f738734b1..3f9b7d562 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -6,6 +6,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwsound/sound.hpp" + #include "../mwrender/renderingmanager.hpp" #include "player.hpp" @@ -152,12 +154,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa setFallbackWeather(foggy,"foggy"); Weather thunderstorm; - thunderstorm.mRainLoopSoundID = "rain heavy"; + thunderstorm.mAmbientLoopSoundID = "rain heavy"; thunderstorm.mRainEffect = "meshes\\raindrop.nif"; setFallbackWeather(thunderstorm,"thunderstorm"); Weather rain; - rain.mRainLoopSoundID = "rain"; + rain.mAmbientLoopSoundID = "rain"; rain.mRainEffect = "meshes\\raindrop.nif"; setFallbackWeather(rain,"rain"); @@ -186,7 +188,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa WeatherManager::~WeatherManager() { - stopSounds(true); + stopSounds(); } void WeatherManager::setWeather(const String& weather, bool instant) @@ -228,6 +230,8 @@ void WeatherManager::setResult(const String& weatherType) mResult.mCloudSpeed = current.mCloudSpeed; mResult.mGlareView = current.mGlareView; mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + mResult.mAmbientSoundVolume = 1.f; + mResult.mEffectFade = 1.f; mResult.mSunColor = current.mSunDiscSunsetColor; mResult.mIsStorm = current.mIsStorm; @@ -341,11 +345,30 @@ void WeatherManager::transition(float factor) mResult.mNight = current.mNight; - mResult.mIsStorm = current.mIsStorm; - mResult.mParticleEffect = current.mParticleEffect; - mResult.mRainEffect = current.mRainEffect; - mResult.mRainSpeed = current.mRainSpeed; - mResult.mRainFrequency = current.mRainFrequency; + if (factor < 0.5) + { + mResult.mIsStorm = current.mIsStorm; + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainEffect = current.mRainEffect; + mResult.mParticleEffect = current.mParticleEffect; + mResult.mRainSpeed = current.mRainSpeed; + mResult.mRainFrequency = current.mRainFrequency; + mResult.mAmbientSoundVolume = 1-(factor*2); + mResult.mEffectFade = mResult.mAmbientSoundVolume; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + } + else + { + mResult.mIsStorm = other.mIsStorm; + mResult.mParticleEffect = other.mParticleEffect; + mResult.mRainEffect = other.mRainEffect; + mResult.mParticleEffect = other.mParticleEffect; + mResult.mRainSpeed = other.mRainSpeed; + mResult.mRainFrequency = other.mRainFrequency; + mResult.mAmbientSoundVolume = 2*(factor-0.5); + mResult.mEffectFade = mResult.mAmbientSoundVolume; + mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; + } } void WeatherManager::update(float duration, bool paused) @@ -361,7 +384,7 @@ void WeatherManager::update(float duration, bool paused) { mRendering->skyDisable(); mRendering->getSkyManager()->setLightningStrength(0.f); - stopSounds(true); + stopSounds(); return; } @@ -541,40 +564,25 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setWeather(mResult); // Play sounds - if (mNextWeather == "") + if (mPlayingSoundID != mResult.mAmbientLoopSoundID) { - std::string ambientSnd = mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID; - if (!ambientSnd.empty() && std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) - { - mSoundsPlaying.push_back(ambientSnd); - MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); - } + stopSounds(); + if (!mResult.mAmbientLoopSoundID.empty()) + mAmbientSound = MWBase::Environment::get().getSoundManager()->playSound(mResult.mAmbientLoopSoundID, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); - std::string rainSnd = mWeatherSettings[mCurrentWeather].mRainLoopSoundID; - if (!rainSnd.empty() && std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) - { - mSoundsPlaying.push_back(rainSnd); - MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); - } + mPlayingSoundID = mResult.mAmbientLoopSoundID; } - - stopSounds(false); + if (mAmbientSound.get()) + mAmbientSound->setVolume(mResult.mAmbientSoundVolume); } -void WeatherManager::stopSounds(bool stopAll) +void WeatherManager::stopSounds() { - std::vector::iterator it = mSoundsPlaying.begin(); - while (it!=mSoundsPlaying.end()) + if (mAmbientSound.get()) { - if (stopAll || - !((*it == mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID) || - (*it == mWeatherSettings[mCurrentWeather].mRainLoopSoundID))) - { - MWBase::Environment::get().getSoundManager()->stopSound(*it); - it = mSoundsPlaying.erase(it); - } - else - ++it; + MWBase::Environment::get().getSoundManager()->stopSound(mAmbientSound); + mAmbientSound.reset(); + mPlayingSoundID.clear(); } } @@ -764,7 +772,7 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, int32_t type) state.load(reader); // reset other temporary state, now that we loaded successfully - stopSounds(true); // let's hope this never throws + stopSounds(); // let's hope this never throws mRegionOverrides.clear(); mRegionMods.clear(); mThunderFlash = 0.0; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 97897fda9..dee9fc52a 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -7,6 +7,8 @@ #include #include +#include "../mwbase/soundmanager.hpp" + namespace ESM { struct Region; @@ -61,10 +63,12 @@ namespace MWWorld bool mIsStorm; std::string mAmbientLoopSoundID; + float mAmbientSoundVolume; std::string mParticleEffect; - std::string mRainEffect; + float mEffectFade; + float mRainSpeed; float mRainFrequency; }; @@ -125,9 +129,6 @@ namespace MWWorld // This is used for Blight, Ashstorm and Blizzard (Bloodmoon) std::string mAmbientLoopSoundID; - // Rain sound effect - std::string mRainLoopSoundID; - // Is this an ash storm / blight storm? If so, the following will happen: // - The particles and clouds will be oriented so they appear to come from the Red Mountain. // - Characters will animate their hand to protect eyes from the storm when looking in its direction (idlestorm animation) @@ -173,7 +174,7 @@ namespace MWWorld */ void update(float duration, bool paused = false); - void stopSounds(bool stopAll); + void stopSounds(); void setHour(const float hour); @@ -206,6 +207,9 @@ namespace MWWorld bool mIsStorm; Ogre::Vector3 mStormDirection; + MWBase::SoundPtr mAmbientSound; + std::string mPlayingSoundID; + MWWorld::Fallback* mFallback; void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; @@ -214,8 +218,6 @@ namespace MWWorld std::map mRegionOverrides; - std::vector mSoundsPlaying; - std::string mCurrentWeather; std::string mNextWeather; From 406cf2b9814cbce5202871103ce7d4dfff1b55e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Dec 2014 11:17:39 +0100 Subject: [PATCH 57/98] disable element visibility buttons that do not apply to the respective cell type --- apps/opencs/view/render/pagedworldspacewidget.cpp | 9 +++++++++ apps/opencs/view/render/pagedworldspacewidget.hpp | 2 ++ apps/opencs/view/render/unpagedworldspacewidget.cpp | 8 ++++++++ apps/opencs/view/render/unpagedworldspacewidget.hpp | 4 ++++ apps/opencs/view/render/worldspacewidget.cpp | 2 -- apps/opencs/view/widget/scenetooltoggle2.cpp | 7 +++++-- apps/opencs/view/widget/scenetooltoggle2.hpp | 2 +- 7 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index e5d542858..764320a70 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -22,6 +22,7 @@ #include "../widget/scenetooltoggle.hpp" #include "../widget/scenetoolmode.hpp" +#include "../widget/scenetooltoggle2.hpp" #include "editmode.hpp" #include "elements.hpp" @@ -212,6 +213,14 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event WorldspaceWidget::mouseDoubleClickEvent(event); } +void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons ( + CSVWidget::SceneToolToggle2 *tool) +{ + WorldspaceWidget::addVisibilitySelectorButtons (tool); + tool->addButton (Element_Terrain, "Terrain"); + tool->addButton (Element_Fog, "Fog", "", true); +} + void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons ( CSVWidget::SceneToolMode *tool) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index ca618d122..3db6ee4ed 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -83,6 +83,8 @@ namespace CSVRender protected: + virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); + virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool); virtual void updateOverlay(); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 07acbe493..62cbdf1e1 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -153,6 +153,14 @@ void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& pare flagAsModified(); } +void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( + CSVWidget::SceneToolToggle2 *tool) +{ + WorldspaceWidget::addVisibilitySelectorButtons (tool); + tool->addButton (Element_Terrain, "Terrain", "", true); + tool->addButton (Element_Fog, "Fog"); +} + std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { Ogre::Vector3 position = getCamera()->getPosition(); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 237cb8f46..d01c3e766 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -60,6 +60,10 @@ namespace CSVRender virtual std::string getStartupInstruction(); + protected: + + virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle2 *tool); + private slots: void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 1f7c41512..51dfcd506 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -263,10 +263,8 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( CSVWidget::SceneToolToggle2 *tool) { tool->addButton (Element_Reference, "References"); - tool->addButton (Element_Terrain, "Terrain"); tool->addButton (Element_Water, "Water"); tool->addButton (Element_Pathgrid, "Pathgrid"); - tool->addButton (Element_Fog, "Fog"); } void CSVRender::WorldspaceWidget::addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool) diff --git a/apps/opencs/view/widget/scenetooltoggle2.cpp b/apps/opencs/view/widget/scenetooltoggle2.cpp index 1c5c11a4d..313e519cb 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.cpp +++ b/apps/opencs/view/widget/scenetooltoggle2.cpp @@ -72,7 +72,7 @@ void CSVWidget::SceneToolToggle2::showPanel (const QPoint& position) } void CSVWidget::SceneToolToggle2::addButton (unsigned int id, - const QString& name, const QString& tooltip) + const QString& name, const QString& tooltip, bool disabled) { std::ostringstream stream; stream << mSingleIcon << id; @@ -84,6 +84,9 @@ void CSVWidget::SceneToolToggle2::addButton (unsigned int id, button->setIconSize (QSize (mIconSize, mIconSize)); button->setFixedSize (mButtonSize, mButtonSize); + if (disabled) + button->setDisabled (true); + mLayout->addWidget (button); ButtonDesc desc; @@ -95,7 +98,7 @@ void CSVWidget::SceneToolToggle2::addButton (unsigned int id, connect (button, SIGNAL (clicked()), this, SLOT (selected())); - if (mButtons.size()==1) + if (mButtons.size()==1 && !disabled) mFirst = button; } diff --git a/apps/opencs/view/widget/scenetooltoggle2.hpp b/apps/opencs/view/widget/scenetooltoggle2.hpp index 4bd9ba26f..0bae780f9 100644 --- a/apps/opencs/view/widget/scenetooltoggle2.hpp +++ b/apps/opencs/view/widget/scenetooltoggle2.hpp @@ -56,7 +56,7 @@ namespace CSVWidget /// \attention After the last button has been added, setSelection must be called at /// least once to finalise the layout. void addButton (unsigned int id, - const QString& name, const QString& tooltip = ""); + const QString& name, const QString& tooltip = "", bool disabled = false); unsigned int getSelection() const; From bfa048e687586af7829f2d3626fbf185ad20be34 Mon Sep 17 00:00:00 2001 From: Paulo Viadanna Date: Tue, 2 Dec 2014 12:42:01 -0200 Subject: [PATCH 58/98] Fix #1734: AI will stop combat if target disappear --- apps/openmw/mwmechanics/aicombat.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 67fd54456..624960632 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -325,6 +325,11 @@ namespace MWMechanics currentAction = prepareNextAction(actor, target); actionCooldown = currentAction->getActionCooldown(); } + + // Stop attacking if target is not seen + if (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(target, actor)) + return true; + if (currentAction.get()) currentAction->getCombatRange(rangeAttack, rangeFollow); From 4e756a2f4a971c62fd9e756d8e6fc7c44f26f5fc Mon Sep 17 00:00:00 2001 From: root Date: Wed, 3 Dec 2014 01:03:27 +0400 Subject: [PATCH 59/98] path to game get through jni --- components/files/androidpath.h | 19 +++++++++++++++++++ components/files/androidpath.hpp | 7 ++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 components/files/androidpath.h diff --git a/components/files/androidpath.h b/components/files/androidpath.h new file mode 100644 index 000000000..3157c067f --- /dev/null +++ b/components/files/androidpath.h @@ -0,0 +1,19 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include + +#ifndef _Included_org_libsdl_app_SDLActivity_getPathToJni +#define _Included_org_libsdl_app_SDLActivity_getPathToJni +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: Java_org_libsdl_app_SDLActivity_getPathToJni + * Method: getPathToJni + * Signature: (I)I + */ +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/components/files/androidpath.hpp b/components/files/androidpath.hpp index 792462fc6..9d47d6d94 100644 --- a/components/files/androidpath.hpp +++ b/components/files/androidpath.hpp @@ -7,12 +7,17 @@ /** * \namespace Files */ + + namespace Files { - +class getJniPath{ +public: const char *getPathFromJni; +}; struct AndroidPath { AndroidPath(const std::string& application_name); + /** * \brief Return path to the user directory. From 85b8fca1f0112a1ea1b84f929007e48c8a7a81a4 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 3 Dec 2014 01:11:50 +0400 Subject: [PATCH 60/98] fixes --- components/files/androidpath.cpp | 46 ++++++++++++++++++++++++++++---- components/files/androidpath.hpp | 4 +-- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index e2f9e948a..117626095 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -5,11 +5,37 @@ #include #include #include +#include "androidpath.h" #include #include + +class Buffer { + public: + static void setData(char const *data); + static char const * getData(); +}; +static char const *path; + +void Buffer::setData(char const *data) +{ + path=data; +} +char const * Buffer::getData() +{ + return path; +} + + +JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) +{ + jboolean iscopy; + Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy)); +} + namespace { + boost::filesystem::path getUserHome() { const char* dir = getenv("HOME"); @@ -53,22 +79,30 @@ AndroidPath::AndroidPath(const std::string& application_name) boost::filesystem::path AndroidPath::getUserConfigPath() const { - return getEnv("XDG_CONFIG_HOME", "/sdcard/libopenmw/config") / mName; + std::string buffer = ""; + buffer = buffer + Buffer::getData() +"/config"; + return getEnv("XDG_CONFIG_HOME", buffer) / mName; } boost::filesystem::path AndroidPath::getUserDataPath() const { - return getEnv("XDG_DATA_HOME", "/sdcard/libopenmw/share") / mName; + std::string buffer = ""; + buffer = buffer + Buffer::getData() +"/share"; + return getEnv("XDG_DATA_HOME", buffer) / mName; } boost::filesystem::path AndroidPath::getCachePath() const { - return getEnv("XDG_CACHE_HOME", "/sdcard/libopenmw/cache") / mName; + std::string buffer = ""; + buffer = buffer + Buffer::getData() +"/cache"; + return getEnv("XDG_CACHE_HOME", buffer) / mName; } boost::filesystem::path AndroidPath::getGlobalConfigPath() const { - boost::filesystem::path globalPath("/sdcard/libopenmw/"); + std::string buffer = ""; + buffer = buffer + Buffer::getData() +"/"; + boost::filesystem::path globalPath(buffer); return globalPath / mName; } @@ -79,7 +113,9 @@ boost::filesystem::path AndroidPath::getLocalPath() const boost::filesystem::path AndroidPath::getGlobalDataPath() const { - boost::filesystem::path globalDataPath("/sdcard/libopenmw/data"); + std::string buffer = ""; + buffer = buffer + Buffer::getData() +"/data"; + boost::filesystem::path globalDataPath(buffer); return globalDataPath / mName; } diff --git a/components/files/androidpath.hpp b/components/files/androidpath.hpp index 9d47d6d94..a8124e6db 100644 --- a/components/files/androidpath.hpp +++ b/components/files/androidpath.hpp @@ -11,9 +11,7 @@ namespace Files { -class getJniPath{ -public: const char *getPathFromJni; -}; + struct AndroidPath { AndroidPath(const std::string& application_name); From e755f692cc015c1700b6c6b479b3def7352a2626 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 3 Dec 2014 09:42:12 +0100 Subject: [PATCH 61/98] silenced some annoying warnings --- apps/wizard/componentselectionpage.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/wizard/componentselectionpage.cpp b/apps/wizard/componentselectionpage.cpp index 956f0f237..1fcde7857 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -62,7 +62,7 @@ void Wizard::ComponentSelectionPage::initializePage() if (field(QLatin1String("installation.new")).toBool() == true) { - morrowindItem->setFlags(morrowindItem->flags() & ~Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + morrowindItem->setFlags((morrowindItem->flags() & ~Qt::ItemIsEnabled) | Qt::ItemIsUserCheckable); morrowindItem->setData(Qt::CheckStateRole, Qt::Checked); componentsList->addItem(morrowindItem); @@ -77,7 +77,7 @@ void Wizard::ComponentSelectionPage::initializePage() if (mWizard->mInstallations[path].hasMorrowind) { morrowindItem->setText(tr("Morrowind\t\t(installed)")); - morrowindItem->setFlags(morrowindItem->flags() & ~Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + morrowindItem->setFlags((morrowindItem->flags() & ~Qt::ItemIsEnabled) | Qt::ItemIsUserCheckable); morrowindItem->setData(Qt::CheckStateRole, Qt::Unchecked); } else { morrowindItem->setText(tr("Morrowind")); @@ -88,7 +88,7 @@ void Wizard::ComponentSelectionPage::initializePage() if (mWizard->mInstallations[path].hasTribunal) { tribunalItem->setText(tr("Tribunal\t\t(installed)")); - tribunalItem->setFlags(tribunalItem->flags() & ~Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + tribunalItem->setFlags((tribunalItem->flags() & ~Qt::ItemIsEnabled) | Qt::ItemIsUserCheckable); tribunalItem->setData(Qt::CheckStateRole, Qt::Unchecked); } else { tribunalItem->setText(tr("Tribunal")); @@ -99,7 +99,7 @@ void Wizard::ComponentSelectionPage::initializePage() if (mWizard->mInstallations[path].hasBloodmoon) { bloodmoonItem->setText(tr("Bloodmoon\t\t(installed)")); - bloodmoonItem->setFlags(bloodmoonItem->flags() & ~Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); + bloodmoonItem->setFlags((bloodmoonItem->flags() & ~Qt::ItemIsEnabled) | Qt::ItemIsUserCheckable); bloodmoonItem->setData(Qt::CheckStateRole, Qt::Unchecked); } else { bloodmoonItem->setText(tr("Bloodmoon")); From 58b6e757e39708f016fd7b386cad8466ee42277f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 3 Dec 2014 15:24:37 +0100 Subject: [PATCH 62/98] fixed another case folding problem regarding OpenCS resources handling --- apps/opencs/model/world/resources.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 8e255bc96..aeef59fe7 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -55,7 +55,8 @@ CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::T std::string file = iter->substr (baseSize+1); mFiles.push_back (file); - mIndex.insert (std::make_pair (file, static_cast (mFiles.size())-1)); + mIndex.insert (std::make_pair ( + Misc::StringUtils::lowerCase (file), static_cast (mFiles.size())-1)); } } } From f2d991505ef97c80c1667256ed6a641351885c05 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 3 Dec 2014 15:31:00 +0100 Subject: [PATCH 63/98] handle other Windows-specific path issues regarding OpenCS resources handling --- apps/opencs/model/world/resources.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index aeef59fe7..13c8df84d 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -55,6 +56,7 @@ CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::T std::string file = iter->substr (baseSize+1); mFiles.push_back (file); + std::replace (file.begin(), file.end(), '\\', '/'); mIndex.insert (std::make_pair ( Misc::StringUtils::lowerCase (file), static_cast (mFiles.size())-1)); } @@ -90,6 +92,8 @@ int CSMWorld::Resources::searchId (const std::string& id) const { std::string id2 = Misc::StringUtils::lowerCase (id); + std::replace (id2.begin(), id2.end(), '\\', '/'); + std::map::const_iterator iter = mIndex.find (id2); if (iter==mIndex.end()) From 329a3558bfb073d670aa05ec88490e3b153fbe29 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 3 Dec 2014 15:36:07 +0100 Subject: [PATCH 64/98] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index c6a5c7169..76efb2760 100644 --- a/credits.txt +++ b/credits.txt @@ -96,6 +96,7 @@ terrorfisch Thomas Luppi (Digmaster) Tom Mason (wheybags) Torben Leif Carrington (TorbenC) +viadanna Vincent Heuken vocollapse From dd0cea21b0ead17a13198f3e584d343c6bb31875 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 1 Dec 2014 23:25:25 +0100 Subject: [PATCH 65/98] Implement overwriting pathgrid records (Fixes #2175) --- apps/openmw/mwworld/store.hpp | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 55c5b8191..469b93f88 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -876,8 +876,36 @@ namespace MWWorld public: void load(ESM::ESMReader &esm, const std::string &id) { - mStatic.push_back(ESM::Pathgrid()); - mStatic.back().load(esm); + + ESM::Pathgrid pathgrid; + pathgrid.load(esm); + + // Try to overwrite existing record + // Can't use search() because we aren't sorted yet + if (!pathgrid.mCell.empty()) + { + for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + if ((*it).mCell == pathgrid.mCell) + { + (*it) = pathgrid; + return; + } + } + } + else + { + for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + if ((*it).mData.mX == pathgrid.mData.mX && (*it).mData.mY == pathgrid.mData.mY) + { + (*it) = pathgrid; + return; + } + } + } + + mStatic.push_back(pathgrid); } size_t getSize() const { From 7faa849cef8ac27f423f037ef5d0fcb89cefbd16 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Dec 2014 01:19:35 +0100 Subject: [PATCH 66/98] Fix fatigue recalculation using older value (oops) --- apps/openmw/mwmechanics/creaturestats.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 7bf027732..21fd2203f 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -147,6 +147,11 @@ namespace MWMechanics if (value != currentValue) { + if(!mIsWerewolf) + mAttributes[index] = value; + else + mWerewolfAttributes[index] = value; + if (index == ESM::Attribute::Intelligence) mRecalcMagicka = true; else if (index == ESM::Attribute::Strength || @@ -164,11 +169,6 @@ namespace MWMechanics setFatigue(fatigue); } } - - if(!mIsWerewolf) - mAttributes[index] = value; - else - mWerewolfAttributes[index] = value; } void CreatureStats::setHealth(const DynamicStat &value) From 3519d23518f9647b1e972d8e73f703c87b1bcd95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Dec 2014 01:37:19 +0100 Subject: [PATCH 67/98] Race dialog: remove incorrect assumption about numeric index in head/hair record IDs --- apps/openmw/mwgui/race.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 444b572b6..ec83b47a7 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -128,11 +128,17 @@ namespace MWGui setRaceId(proto.mRace); recountParts(); - std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); - mFaceIndex = boost::lexical_cast(index) - 1; + for (unsigned int i=0; i(index) - 1; + for (unsigned int i=0; isetImageTexture (textureName); From e6c59f5585e73781c0c78c7d74f035fed8878e0a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Dec 2014 18:07:32 +0100 Subject: [PATCH 68/98] Revert "Allow NIF rotation matrices that include scale values" This reverts commit f57ddec6a22baf8823b93bd5e99df16796ac7d61. Conflicts: components/nif/nifstream.hpp (Fixes #2168) --- components/nif/data.hpp | 6 +++--- components/nif/nifstream.cpp | 2 +- components/nif/niftypes.hpp | 2 +- components/nif/node.cpp | 5 ++--- components/nifogre/mesh.cpp | 7 +++---- components/nifogre/skeleton.cpp | 14 +++----------- 6 files changed, 13 insertions(+), 23 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index f3b5a27f8..5efd0d6c9 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -272,7 +272,7 @@ class NiSkinData : public Record public: struct BoneTrafo { - Ogre::Matrix3 rotationScale; // Rotation offset from bone, non-uniform scale + Ogre::Matrix3 rotation; // Rotation offset from bone? Ogre::Vector3 trans; // Translation float scale; // Probably scale (always 1) }; @@ -295,7 +295,7 @@ public: void read(NIFStream *nif) { - trafo.rotationScale = nif->getMatrix3(); + trafo.rotation = nif->getMatrix3(); trafo.trans = nif->getVector3(); trafo.scale = nif->getFloat(); @@ -307,7 +307,7 @@ public: { BoneInfo &bi = bones[i]; - bi.trafo.rotationScale = nif->getMatrix3(); + bi.trafo.rotation = nif->getMatrix3(); bi.trafo.trans = nif->getVector3(); bi.trafo.scale = nif->getFloat(); bi.unknown = nif->getVector4(); diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 527d1a2af..a6fd5ef5a 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -76,7 +76,7 @@ Transformation NIFStream::getTrafo() { Transformation t; t.pos = getVector3(); - t.rotationScale = getMatrix3(); + t.rotation = getMatrix3(); t.scale = getFloat(); return t; } diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index f9235ec45..786c48b65 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -35,7 +35,7 @@ namespace Nif struct Transformation { Ogre::Vector3 pos; - Ogre::Matrix3 rotationScale; + Ogre::Matrix3 rotation; float scale; static const Transformation& getIdentity() diff --git a/components/nif/node.cpp b/components/nif/node.cpp index 7529e602d..b7ca98113 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -42,9 +42,8 @@ void Node::getProperties(const Nif::NiTexturingProperty *&texprop, Ogre::Matrix4 Node::getLocalTransform() const { - Ogre::Matrix4 mat4 = Ogre::Matrix4(trafo.rotationScale); - mat4.setTrans(trafo.pos); - mat4.setScale(Ogre::Vector3(trafo.rotationScale[0][0], trafo.rotationScale[1][1], trafo.rotationScale[2][2]) * trafo.scale); + Ogre::Matrix4 mat4 = Ogre::Matrix4(Ogre::Matrix4::IDENTITY); + mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation)); return mat4; } diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c952e664d..af73df637 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -138,10 +138,9 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape const Nif::NodeList &bones = skin->bones; for(size_t b = 0;b < bones.length();b++) { - const Ogre::Matrix3& rotationScale = data->bones[b].trafo.rotationScale; - Ogre::Matrix4 mat (rotationScale); - mat.setTrans(data->bones[b].trafo.trans); - mat.setScale(Ogre::Vector3(rotationScale[0][0], rotationScale[1][1], rotationScale[2][2]) * data->bones[b].trafo.scale); + Ogre::Matrix4 mat; + mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), + Ogre::Quaternion(data->bones[b].trafo.rotation)); mat = bones[b]->getWorldTransform() * mat; const std::vector &weights = data->bones[b].weights; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index a3fade5b2..db6a753c5 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -36,17 +36,9 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, if(parent) parent->addChild(bone); mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); - // decompose the local transform into position, scale and orientation. - // this is required for cases where the rotationScale matrix includes scaling, which the NIF format allows :( - // the code would look a bit nicer if Ogre allowed setting the transform matrix of a Bone directly, but we can't do that. - Ogre::Matrix4 mat(node->getLocalTransform()); - Ogre::Vector3 position, scale; - Ogre::Quaternion orientation; - mat.decomposition(position, scale, orientation); - bone->setOrientation(orientation); - bone->setPosition(position); - bone->setScale(scale); - + bone->setOrientation(node->trafo.rotation); + bone->setPosition(node->trafo.pos); + bone->setScale(Ogre::Vector3(node->trafo.scale)); bone->setBindingPose(); if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ From 14ae6d28b09489ca7fc9599d5b27979f6c6fd8c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Dec 2014 18:42:13 +0100 Subject: [PATCH 69/98] Fix being able to jump when overencumbered --- apps/openmw/mwclass/npc.cpp | 3 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 1 + apps/openmw/mwmechanics/character.cpp | 45 +++++++++++++------------ 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d3f86c03b..641edcc83 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -969,6 +969,9 @@ namespace MWClass float Npc::getJump(const MWWorld::Ptr &ptr) const { + if(getEncumbrance(ptr) > getCapacity(ptr)) + return 0.f; + const NpcCustomData *npcdata = static_cast(ptr.getRefData().getCustomData()); const GMST& gmst = getGmst(); const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 48acd22ba..b0d2bfeff 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -371,6 +371,7 @@ namespace MWInput { mPlayer->setUpDown (1); triedToMove = true; + mOverencumberedMessageDelay = 0.f; } if (mAlwaysRunActive) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 11484ac49..2e4f76c1a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1414,29 +1414,32 @@ void CharacterController::update(float duration) { // Started a jump. float z = cls.getJump(mPtr); - if(vec.x == 0 && vec.y == 0) - vec = Ogre::Vector3(0.0f, 0.0f, z); - else + if (z > 0) { - Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); - vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; + if(vec.x == 0 && vec.y == 0) + vec = Ogre::Vector3(0.0f, 0.0f, z); + else + { + Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); + vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; + } + + // advance acrobatics + if (mPtr.getRefData().getHandle() == "player") + cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); + + // decrease fatigue + const MWWorld::Store &gmst = world->getStore().get(); + const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat(); + const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat(); + float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr); + if (normalizedEncumbrance > 1) + normalizedEncumbrance = 1; + const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; + DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); + fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); + cls.getCreatureStats(mPtr).setFatigue(fatigue); } - - // advance acrobatics - if (mPtr.getRefData().getHandle() == "player") - cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); - - // decrease fatigue - const MWWorld::Store &gmst = world->getStore().get(); - const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat(); - const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat(); - float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr); - if (normalizedEncumbrance > 1) - normalizedEncumbrance = 1; - const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; - DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); - fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); - cls.getCreatureStats(mPtr).setFatigue(fatigue); } else if(mJumpState == JumpState_InAir) { From b650338d6934be67ccdebdf9c6350e8b39b050d7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Dec 2014 18:42:40 +0100 Subject: [PATCH 70/98] Implement drawMode of NiStencilProperty (Feature #1057) --- components/nif/node.cpp | 7 +++++-- components/nif/node.hpp | 3 ++- components/nifogre/material.cpp | 28 ++++++++++++++++++++++++++++ components/nifogre/material.hpp | 2 ++ components/nifogre/mesh.cpp | 5 +++-- components/nifogre/ogrenifloader.cpp | 8 +++++--- files/materials/objects.mat | 1 + 7 files changed, 46 insertions(+), 8 deletions(-) diff --git a/components/nif/node.cpp b/components/nif/node.cpp index b7ca98113..fb68da548 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -9,10 +9,11 @@ void Node::getProperties(const Nif::NiTexturingProperty *&texprop, const Nif::NiVertexColorProperty *&vertprop, const Nif::NiZBufferProperty *&zprop, const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop) const + const Nif::NiWireframeProperty *&wireprop, + const Nif::NiStencilProperty *&stencilprop) const { if(parent) - parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); for(size_t i = 0;i < props.length();i++) { @@ -35,6 +36,8 @@ void Node::getProperties(const Nif::NiTexturingProperty *&texprop, specprop = static_cast(pr); else if(pr->recType == Nif::RC_NiWireframeProperty) wireprop = static_cast(pr); + else if (pr->recType == Nif::RC_NiStencilProperty) + stencilprop = static_cast(pr); else std::cerr<< "Unhandled property type: "<recName <colors.size() != 0); @@ -205,6 +207,20 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, } } + if(stencilprop) + { + drawMode = stencilprop->data.drawMode; + if (stencilprop->data.enabled) + warn("Unhandled stencil test in "+name); + + Nif::ControllerPtr ctrls = stencilprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled stencil controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + // Material if(matprop) { @@ -249,8 +265,13 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, for(int i = 0;i < 7;i++) { if(!texName[i].empty()) + { boost::hash_combine(h, texName[i]); + boost::hash_combine(h, texprop->textures[i].clamp); + boost::hash_combine(h, texprop->textures[i].uvSet); + } } + boost::hash_combine(h, drawMode); boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); @@ -308,6 +329,13 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); } + if (drawMode == 1) + instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("clockwise"))); + else if (drawMode == 2) + instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("anticlockwise"))); + else if (drawMode == 3) + instance->setProperty("cullmode", sh::makeProperty(new sh::StringValue("none"))); + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); diff --git a/components/nifogre/material.hpp b/components/nifogre/material.hpp index d485439cf..6be52d1a5 100644 --- a/components/nifogre/material.hpp +++ b/components/nifogre/material.hpp @@ -18,6 +18,7 @@ namespace Nif class NiZBufferProperty; class NiSpecularProperty; class NiWireframeProperty; + class NiStencilProperty; } namespace NifOgre @@ -41,6 +42,7 @@ public: const Nif::NiZBufferProperty *zprop, const Nif::NiSpecularProperty *specprop, const Nif::NiWireframeProperty *wireprop, + const Nif::NiStencilProperty *stencilprop, bool &needTangents, bool particleMaterial=false); }; diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index af73df637..4932dd009 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -320,13 +320,14 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; const Nif::NiWireframeProperty *wireprop = NULL; + const Nif::NiStencilProperty *stencilprop = NULL; bool needTangents = false; - shape->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + shape->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, - wireprop, needTangents); + wireprop, stencilprop, needTangents); if(matname.length() > 0) sub->setMaterialName(matname); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index dcc34f627..053adfb5b 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -732,7 +732,8 @@ class NIFObjectLoader const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; const Nif::NiWireframeProperty *wireprop = NULL; - node->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + const Nif::NiStencilProperty *stencilprop = NULL; + node->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : @@ -889,13 +890,14 @@ class NIFObjectLoader const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; const Nif::NiWireframeProperty *wireprop = NULL; + const Nif::NiStencilProperty *stencilprop = NULL; bool needTangents = false; - partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, stencilprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, texprop, matprop, alphaprop, vertprop, zprop, specprop, - wireprop, needTangents, + wireprop, stencilprop, needTangents, // MW doesn't light particles, but the MaterialProperty // used still has lighting, so that must be ignored. true)); diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 149160760..7d3085b0f 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -67,6 +67,7 @@ material openmw_objects_base depth_check $depth_check transparent_sorting $transparent_sorting polygon_mode $polygon_mode + cull_hardware $cullmode texture_unit diffuseMap { From 75b0da5dce41960b3e9af9fdb69db1d9b3e20fdc Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Dec 2014 21:04:38 +0100 Subject: [PATCH 71/98] Don't updateBoneTree for non-skinned parts (Fixes #2124) --- apps/openmw/mwrender/npcanimation.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c43d3663e..363a36376 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -60,6 +60,21 @@ std::string getVampireHead(const std::string& race, bool female) return "meshes\\" + sVampireMapping[thisCombination]->mModel; } +bool isSkinned (NifOgre::ObjectScenePtr scene) +{ + if (scene->mSkelBase == NULL) + return false; + for(size_t j = 0; j < scene->mEntities.size(); j++) + { + Ogre::Entity *ent = scene->mEntities[j]; + if(scene->mSkelBase != ent && ent->hasSkeleton()) + { + return true; + } + } + return false; +} + } @@ -611,10 +626,11 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) for(;ctrl != mObjectParts[i]->mControllers.end();++ctrl) ctrl->update(); - Ogre::Entity *ent = mObjectParts[i]->mSkelBase; - if(!ent) continue; - updateSkeletonInstance(baseinst, ent->getSkeleton()); - ent->getAllAnimationStates()->_notifyDirty(); + if (!isSkinned(mObjectParts[i])) + continue; + + updateSkeletonInstance(baseinst, mObjectParts[i]->mSkelBase->getSkeleton()); + mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); } return ret; @@ -697,7 +713,8 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g } } - updateSkeletonInstance(mSkelBase->getSkeleton(), skel); + if (isSkinned(mObjectParts[type])) + updateSkeletonInstance(mSkelBase->getSkeleton(), skel); } std::vector >::iterator ctrl(mObjectParts[type]->mControllers.begin()); From fee08f97edf41eab9f28e538ae9bca4205b0877f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Dec 2014 00:02:14 +0100 Subject: [PATCH 72/98] Fix crash in character preview for non-existing meshes (Fixes #2128) --- apps/openmw/mwgui/race.cpp | 10 +++++++++- apps/openmw/mwrender/characterpreview.cpp | 5 ++++- apps/openmw/mwrender/npcanimation.cpp | 10 +++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index ec83b47a7..bcb766f8f 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -313,7 +313,15 @@ namespace MWGui record.mHead = mAvailableHeads[mFaceIndex]; record.mHair = mAvailableHairs[mHairIndex]; - mPreview->setPrototype(record); + try + { + mPreview->setPrototype(record); + } + catch (std::exception& e) + { + std::cerr << "Error creating preview: " << e.what() << std::endl; + } + mPreviewDirty = true; } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index d9c953133..92d0bcd55 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -115,8 +115,8 @@ namespace MWRender void CharacterPreview::rebuild() { - assert(mAnimation); delete mAnimation; + mAnimation = NULL; mAnimation = new NpcAnimation(mCharacter, mNode, 0, true, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); @@ -187,6 +187,9 @@ namespace MWRender void InventoryPreview::update() { + if (!mAnimation) + return; + mAnimation->updateParts(); MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 363a36376..d20e89324 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -676,7 +676,15 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g removeIndividualPart(type); mPartslots[type] = group; mPartPriorities[type] = priority; - mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type), enchantedGlow, glowColor); + try + { + mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type), enchantedGlow, glowColor); + } + catch (std::exception& e) + { + std::cerr << "Error adding NPC part: " << e.what() << std::endl; + return false; + } if (!mSoundsDisabled) { From e67cf96250db8d1d11dc860d664a4b0682e8f39e Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 5 Dec 2014 01:09:42 +1100 Subject: [PATCH 73/98] Allow only one instance of OpenCS. Only tested on windows x64. --- apps/opencs/editor.cpp | 57 +++++++++++++++++++++++++++++++++++++++--- apps/opencs/editor.hpp | 4 +++ apps/opencs/main.cpp | 2 +- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index bef83b8ac..dc4044fea 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -22,7 +22,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) : mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), mPhysicsManager (0), - mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) + mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL), mPid(""), mLock() { std::pair > config = readConfig(); @@ -70,7 +70,10 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) } CS::Editor::~Editor () -{} +{ + if(mServer && boost::filesystem::exists(mPid)) + remove(mPid.string().c_str()); // ignore error +} void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) { @@ -233,7 +236,54 @@ void CS::Editor::showSettings() bool CS::Editor::makeIPCServer() { - mServer = new QLocalServer(this); + try + { + mPid = boost::filesystem::temp_directory_path(); + mPid += "opencs.pid"; + bool pidExists = boost::filesystem::exists(mPid); + + boost::filesystem::ofstream tempFile(mPid); + + mLock = boost::interprocess::file_lock(mPid.string().c_str()); + if(!mLock.try_lock()) + { + std::cerr << "OpenCS already running." << std::endl; + return false; + } + +#ifdef _WIN32 + tempFile << GetCurrentProcessId() << std::endl; +#else + tempFile << getpid() << std::endl; +#endif + tempFile.close(); + + mServer = new QLocalServer(this); + + if(pidExists) + { + // hack to get the temp directory path + mServer->listen("dummy"); + QString fullPath = mServer->fullServerName(); + mServer->close(); + fullPath.remove(QRegExp("dummy$")); + fullPath += mIpcServerName; + if(boost::filesystem::exists(fullPath.toStdString().c_str())) + { + // TODO: compare pid of the current process with that in the file + std::cout << "Detected unclean shutdown." << std::endl; + // delete the stale file + if(remove(fullPath.toStdString().c_str())) + std::cerr << "ERROR removing stale connection file" << std::endl; + } + } + } + + catch(const std::exception& e) + { + std::cerr << "ERROR " << e.what() << std::endl; + return false; + } if(mServer->listen(mIpcServerName)) { @@ -242,6 +292,7 @@ bool CS::Editor::makeIPCServer() } mServer->close(); + mServer = NULL; return false; } diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index d55b0e873..c8a6c43c3 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -3,6 +3,8 @@ #include +#include + #include #include #include @@ -54,6 +56,8 @@ namespace CS CSVDoc::FileDialog mFileDialog; boost::filesystem::path mLocal; boost::filesystem::path mResources; + boost::filesystem::path mPid; + boost::interprocess::file_lock mLock; bool mFsStrict; void setupDataFiles (const Files::PathContainer& dataDirs); diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index b184a1ef1..dd20324d1 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -83,7 +83,7 @@ int main(int argc, char *argv[]) if(!editor.makeIPCServer()) { editor.connectToIPCServer(); - // return 0; + return 0; } shinyFactory = editor.setupGraphics(); From 07f10a014071bbe642ac463683c79daf8e964762 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 5 Dec 2014 01:32:20 +1100 Subject: [PATCH 74/98] Use append syntax compatible with older versions of boost. --- apps/opencs/editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index dc4044fea..2aee21d38 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -239,7 +239,7 @@ bool CS::Editor::makeIPCServer() try { mPid = boost::filesystem::temp_directory_path(); - mPid += "opencs.pid"; + mPid /= "opencs.pid"; bool pidExists = boost::filesystem::exists(mPid); boost::filesystem::ofstream tempFile(mPid); From 6731afc79c44a591887b0ef91d9c2c6c2468162c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 5 Dec 2014 03:59:16 +1100 Subject: [PATCH 75/98] Use float for setting skill use values. Should resolve bug #2183. --- apps/opencs/model/world/columnimp.hpp | 2 +- apps/opencs/view/world/util.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 6f830e6e3..eba73cf0b 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -272,7 +272,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - record2.mData.mUseValue[mIndex] = data.toInt(); + record2.mData.mUseValue[mIndex] = data.toFloat(); record.setModified (record2); } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index f987c8d9f..c65e12c60 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -173,6 +173,8 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO { QDoubleSpinBox *dsb = new QDoubleSpinBox(parent); dsb->setRange(FLT_MIN, FLT_MAX); + dsb->setSingleStep(0.01f); + dsb->setDecimals(3); return dsb; } From ab693f1f649c497f9d0b00e2491ed23eb26a7c86 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 5 Dec 2014 07:50:03 +1100 Subject: [PATCH 76/98] Workaround file lock being lost if the same file is closed elsewhere in the program (see https://svn.boost.org/trac/boost/ticket/3582) --- apps/opencs/editor.cpp | 11 ++++++----- apps/opencs/editor.hpp | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 9fe974d86..f609b80b7 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -72,8 +72,10 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) CS::Editor::~Editor () { + mPidFile.close(); + if(mServer && boost::filesystem::exists(mPid)) - remove(mPid.string().c_str()); // ignore error + remove(mPid.string().c_str()); // ignore any error // cleanup global resources used by OEngine delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); @@ -246,7 +248,7 @@ bool CS::Editor::makeIPCServer() mPid /= "opencs.pid"; bool pidExists = boost::filesystem::exists(mPid); - boost::filesystem::ofstream tempFile(mPid); + mPidFile.open(mPid); mLock = boost::interprocess::file_lock(mPid.string().c_str()); if(!mLock.try_lock()) @@ -256,11 +258,10 @@ bool CS::Editor::makeIPCServer() } #ifdef _WIN32 - tempFile << GetCurrentProcessId() << std::endl; + mPidFile << GetCurrentProcessId() << std::endl; #else - tempFile << getpid() << std::endl; + mPidFile << getpid() << std::endl; #endif - tempFile.close(); mServer = new QLocalServer(this); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 30a031309..273f0825b 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -56,6 +57,7 @@ namespace CS boost::filesystem::path mResources; boost::filesystem::path mPid; boost::interprocess::file_lock mLock; + boost::filesystem::ofstream mPidFile; bool mFsStrict; void setupDataFiles (const Files::PathContainer& dataDirs); From 83dcf9ce4bb7fd2d78c5e1ef0395eceb58505f8d Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Dec 2014 02:17:15 +0100 Subject: [PATCH 77/98] Overwrite existing records in IndexedStore (Fixes #2182) --- apps/openmw/mwgui/tooltips.cpp | 4 +- .../mwmechanics/mechanicsmanagerimp.cpp | 4 +- apps/openmw/mwworld/store.hpp | 66 ++++--------------- 3 files changed, 18 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 4608010ac..396c8fa48 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -633,8 +633,8 @@ namespace MWGui MWWorld::Store::iterator it = skills.begin(); for (; it != skills.end(); ++it) { - if (it->mData.mSpecialization == specId) - specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->mIndex] + "}"; + if (it->second.mData.mSpecialization == specId) + specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->first] + "}"; } widget->setUserString("Caption_CenteredCaptionText", specText); widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b4edf44aa..9cafe9b3c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -143,9 +143,9 @@ namespace MWMechanics MWWorld::Store::iterator iter = skills.begin(); for (; iter != skills.end(); ++iter) { - if (iter->mData.mSpecialization==class_->mData.mSpecialization) + if (iter->second.mData.mSpecialization==class_->mData.mSpecialization) { - int index = iter->mIndex; + int index = iter->first; if (index>=0 && index<27) { diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 469b93f88..907d9bd43 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -1015,24 +1015,15 @@ namespace MWWorld template class IndexedStore { - struct Compare - { - bool operator()(const T &x, const T &y) const { - return x.mIndex < y.mIndex; - } - }; protected: - std::vector mStatic; + typedef typename std::map Static; + Static mStatic; public: - typedef typename std::vector::const_iterator iterator; + typedef typename std::map::const_iterator iterator; IndexedStore() {} - IndexedStore(unsigned int size) { - mStatic.reserve(size); - } - iterator begin() const { return mStatic.begin(); } @@ -1041,10 +1032,14 @@ namespace MWWorld return mStatic.end(); } - /// \todo refine loading order void load(ESM::ESMReader &esm) { - mStatic.push_back(T()); - mStatic.back().load(esm); + T record; + record.load(esm); + + // Try to overwrite existing record + std::pair found = mStatic.insert(std::make_pair(record.mIndex, record)); + if (found.second) + found.first->second = record; } int getSize() const { @@ -1052,40 +1047,13 @@ namespace MWWorld } void setUp() { - /// \note This method sorts indexed values for further - /// searches. Every loaded item is present in storage, but - /// latest loaded shadows any previous while searching. - /// If memory cost will be too high, it is possible to remove - /// unused values. - - Compare cmp; - - std::stable_sort(mStatic.begin(), mStatic.end(), cmp); - - typename std::vector::iterator first, next; - next = first = mStatic.begin(); - - while (first != mStatic.end() && ++next != mStatic.end()) { - while (next != mStatic.end() && !cmp(*first, *next)) { - ++next; - } - if (first != --next) { - std::swap(*first, *next); - } - first = ++next; - } } const T *search(int index) const { - T item; - item.mIndex = index; - - iterator it = - std::lower_bound(mStatic.begin(), mStatic.end(), item, Compare()); - if (it != mStatic.end() && it->mIndex == index) { - return &(*it); - } - return 0; + typename Static::const_iterator it = mStatic.find(index); + if (it != mStatic.end()) + return &(it->second); + return NULL; } const T *find(int index) const { @@ -1103,18 +1071,12 @@ namespace MWWorld struct Store : public IndexedStore { Store() {} - Store(unsigned int size) - : IndexedStore(size) - {} }; template <> struct Store : public IndexedStore { Store() {} - Store(unsigned int size) - : IndexedStore(size) - {} }; template <> From a67e7c64eadbfe23aa20214f44a5a68c95a40e35 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Dec 2014 15:58:22 +0100 Subject: [PATCH 78/98] Optimize pathgrid store --- apps/openmw/mwworld/store.hpp | 124 ++++++---------------------------- 1 file changed, 20 insertions(+), 104 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 907d9bd43..5966a99b9 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -842,36 +842,12 @@ namespace MWWorld template <> class Store : public StoreBase { - public: - typedef std::vector::const_iterator iterator; - private: - std::vector mStatic; + typedef std::map Interior; + typedef std::map, ESM::Pathgrid> Exterior; - std::vector::iterator mIntBegin, mIntEnd, mExtBegin, mExtEnd; - - struct IntExtOrdering - { - bool operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { - // interior pathgrids precedes exterior ones (x < y) - if ((x.mData.mX == 0 && x.mData.mY == 0) && - (y.mData.mX != 0 || y.mData.mY != 0)) - { - return true; - } - return false; - } - }; - - struct ExtCompare - { - bool operator()(const ESM::Pathgrid &x, const ESM::Pathgrid &y) const { - if (x.mData.mX == y.mData.mX) { - return x.mData.mY < y.mData.mY; - } - return x.mData.mX < y.mData.mX; - } - }; + Interior mInt; + Exterior mExt; public: @@ -881,65 +857,33 @@ namespace MWWorld pathgrid.load(esm); // Try to overwrite existing record - // Can't use search() because we aren't sorted yet if (!pathgrid.mCell.empty()) { - for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - if ((*it).mCell == pathgrid.mCell) - { - (*it) = pathgrid; - return; - } - } + std::pair found = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); + if (found.second) + found.first->second = pathgrid; } else { - for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - if ((*it).mData.mX == pathgrid.mData.mX && (*it).mData.mY == pathgrid.mData.mY) - { - (*it) = pathgrid; - return; - } - } + std::pair found = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), + pathgrid)); + if (found.second) + found.first->second = pathgrid; } - - mStatic.push_back(pathgrid); } size_t getSize() const { - return mStatic.size(); + return mInt.size() + mExt.size(); } void setUp() { - IntExtOrdering cmp; - std::sort(mStatic.begin(), mStatic.end(), cmp); - - ESM::Pathgrid pg; - pg.mData.mX = pg.mData.mY = 1; - mExtBegin = - std::lower_bound(mStatic.begin(), mStatic.end(), pg, cmp); - mExtEnd = mStatic.end(); - - mIntBegin = mStatic.begin(); - mIntEnd = mExtBegin; - - std::sort(mIntBegin, mIntEnd, RecordCmp()); - std::sort(mExtBegin, mExtEnd, ExtCompare()); } const ESM::Pathgrid *search(int x, int y) const { - ESM::Pathgrid pg; - pg.mData.mX = x; - pg.mData.mY = y; - - iterator it = - std::lower_bound(mExtBegin, mExtEnd, pg, ExtCompare()); - if (it != mExtEnd && it->mData.mX == x && it->mData.mY == y) { - return &(*it); - } - return 0; + Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); + if (it != mExt.end()) + return &(it->second); + return NULL; } const ESM::Pathgrid *find(int x, int y) const { @@ -953,14 +897,10 @@ namespace MWWorld } const ESM::Pathgrid *search(const std::string &name) const { - ESM::Pathgrid pg; - pg.mCell = name; - - iterator it = std::lower_bound(mIntBegin, mIntEnd, pg, RecordCmp()); - if (it != mIntEnd && Misc::StringUtils::ciEqual(it->mCell, name)) { - return &(*it); - } - return 0; + Interior::const_iterator it = mInt.find(name); + if (it != mInt.end()) + return &(it->second); + return NULL; } const ESM::Pathgrid *find(const std::string &name) const { @@ -986,30 +926,6 @@ namespace MWWorld } return find(cell.mData.mX, cell.mData.mY); } - - iterator begin() const { - return mStatic.begin(); - } - - iterator end() const { - return mStatic.end(); - } - - iterator interiorPathsBegin() const { - return mIntBegin; - } - - iterator interiorPathsEnd() const { - return mIntEnd; - } - - iterator exteriorPathsBegin() const { - return mExtBegin; - } - - iterator exteriorPathsEnd() const { - return mExtEnd; - } }; template From 65536f085768fd1d966a603a7e7f4d48f407da8b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Dec 2014 18:00:30 +0100 Subject: [PATCH 79/98] Load initial particle system state from NIF files (Fixes #2178) --- apps/openmw/mwrender/animation.cpp | 4 -- apps/openmw/mwrender/npcanimation.cpp | 4 -- components/nifogre/ogrenifloader.cpp | 82 +++++++++++++++++++++++++++ components/nifogre/ogrenifloader.hpp | 4 ++ 4 files changed, 86 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 548906cdf..ecaaba0b9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -114,10 +114,6 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly) mObjectRoot = (!baseonly ? NifOgre::Loader::createObjects(mInsert, mdlname) : NifOgre::Loader::createObjectBase(mInsert, mdlname)); - // Fast forward auto-play particles, which will have been set up as Emitting by the loader. - for (unsigned int i=0; imParticles.size(); ++i) - mObjectRoot->mParticles[i]->fastForward(1, 0.1); - if(mObjectRoot->mSkelBase) { mSkelBase = mObjectRoot->mSkelBase; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d20e89324..f2bc3df95 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -571,10 +571,6 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model std::for_each(objects->mEntities.begin(), objects->mEntities.end(), SetObjectGroup(group)); std::for_each(objects->mParticles.begin(), objects->mParticles.end(), SetObjectGroup(group)); - // Fast forward auto-play particles, which will have been set up as Emitting by the loader. - for (unsigned int i=0; imParticles.size(); ++i) - objects->mParticles[i]->fastForward(1, 0.1); - if(objects->mSkelBase) { Ogre::AnimationStateSet *aset = objects->mSkelBase->getAllAnimationStates(); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 053adfb5b..b18a88d14 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -161,6 +161,38 @@ void ObjectScene::rotateBillboardNodes(Ogre::Camera *camera) } } +void ObjectScene::_notifyAttached() +{ + // convert initial particle positions to world space for world-space particle systems + // this can't be done on creation because the particle system is not in its correct world space position yet + for (std::vector::iterator it = mParticles.begin(); it != mParticles.end(); ++it) + { + Ogre::ParticleSystem* psys = *it; + if (psys->getKeepParticlesInLocalSpace()) + continue; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + +#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + Ogre::Vector3& position = p->mPosition; + Ogre::Vector3& direction = p->mDirection; +#else + Ogre::Vector3& position = p->position; + Ogre::Vector3& direction = p->direction; +#endif + + position = + (psys->getParentNode()->_getDerivedOrientation() * + (psys->getParentNode()->_getDerivedScale() * position)) + + psys->getParentNode()->_getDerivedPosition(); + direction = + (psys->getParentNode()->_getDerivedOrientation() * direction); + } + } +} + // Animates a texture class FlipController { @@ -949,6 +981,8 @@ class NIFObjectLoader createParticleEmitterAffectors(partsys, partctrl, trgtbone, scene->mSkelBase->getName()); } + createParticleInitialState(partsys, particledata, partctrl); + Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : Ogre::ControllerValueRealPtr()); @@ -975,6 +1009,50 @@ class NIFObjectLoader createMaterialControllers(partnode, partsys, animflags, scene); } + static void createParticleInitialState(Ogre::ParticleSystem* partsys, const Nif::NiAutoNormalParticlesData* particledata, + const Nif::NiParticleSystemController* partctrl) + { + partsys->_update(0.f); // seems to be required to allocate mFreeParticles + int i=0; + for (std::vector::const_iterator it = partctrl->particles.begin(); + iactiveCount && it != partctrl->particles.end(); ++it, ++i) + { + const Nif::NiParticleSystemController::Particle& particle = *it; + + Ogre::Particle* created = partsys->createParticle(); + if (!created) + break; + +#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + Ogre::Vector3& position = created->mPosition; + Ogre::Vector3& direction = created->mDirection; + Ogre::ColourValue& colour = created->mColour; + float& totalTimeToLive = created->mTotalTimeToLive; + float& timeToLive = created->mTimeToLive; +#else + Ogre::Vector3& position = created->position; + Ogre::Vector3& direction = created->direction; + Ogre::ColourValue& colour = created->colour; + float& totalTimeToLive = created->totalTimeToLive; + float& timeToLive = created->timeToLive; +#endif + + direction = particle.velocity; + position = particledata->vertices.at(particle.vertex); + + if (particle.vertex < int(particledata->colors.size())) + { + Ogre::Vector4 partcolour = particledata->colors.at(particle.vertex); + colour = Ogre::ColourValue(partcolour.x, partcolour.y, partcolour.z, partcolour.w); + } + else + colour = Ogre::ColourValue(1.f, 1.f, 1.f, 1.f); + float size = particledata->sizes.at(particle.vertex); + created->setDimensions(size, size); + totalTimeToLive = std::max(0.f, particle.lifespan); + timeToLive = std::max(0.f, particle.lifespan - particle.lifetime); + } + } static void createNodeControllers(const Nif::NIFFilePtr& nif, const std::string &name, Nif::ControllerPtr ctrl, ObjectScenePtr scene, int animflags) { @@ -1275,6 +1353,8 @@ ObjectScenePtr Loader::createObjects(Ogre::SceneNode *parentNode, std::string na parentNode->attachObject(entity); } + scene->_notifyAttached(); + return scene; } @@ -1342,6 +1422,8 @@ ObjectScenePtr Loader::createObjects(Ogre::Entity *parent, const std::string &bo } } + scene->_notifyAttached(); + return scene; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index abadd38de..485495a38 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -84,6 +84,10 @@ struct ObjectScene { void rotateBillboardNodes(Ogre::Camera* camera); void setVisibilityFlags (unsigned int flags); + + // This is called internally by the OgreNifLoader once all elements of the + // scene have been attached to their respective nodes. + void _notifyAttached(); }; typedef Ogre::SharedPtr ObjectScenePtr; From 5a2564907634f37ff63b87b3bf752ce8ee5c1df6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Dec 2014 20:58:03 +0100 Subject: [PATCH 80/98] Implement XYZ rotation keys support (Fixes #1067) --- components/nif/data.hpp | 16 ++++++++-------- components/nif/nifkey.hpp | 6 ++---- components/nifogre/ogrenifloader.cpp | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 5efd0d6c9..d9de12fb5 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -350,8 +350,11 @@ struct NiMorphData : public Record struct NiKeyframeData : public Record { QuaternionKeyMap mRotations; - //\FIXME mXYZ_Keys are read, but not used. - FloatKeyMap mXYZ_Keys; + + FloatKeyMap mXRotations; + FloatKeyMap mYRotations; + FloatKeyMap mZRotations; + Vector3KeyMap mTranslations; FloatKeyMap mScales; @@ -362,12 +365,9 @@ struct NiKeyframeData : public Record { //Chomp unused float nif->getFloat(); - for(size_t i=0;i<3;++i) - { - //Read concatenates items together. - mXYZ_Keys.read(nif,true); - } - nif->file->warn("XYZ_ROTATION_KEY read, but not used!"); + mXRotations.read(nif, true); + mYRotations.read(nif, true); + mZRotations.read(nif, true); } mTranslations.read(nif); mScales.read(nif); diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index b0db80914..cb8142720 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -49,9 +49,7 @@ struct KeyMapT { if(count == 0 && !force) return; - //If we aren't forcing things, make sure that read clears any previous keys - if(!force) - mKeys.clear(); + mKeys.clear(); mInterpolationType = nif->getUInt(); @@ -88,7 +86,7 @@ struct KeyMapT { //XYZ keys aren't actually read here. //data.hpp sees that the last type read was sXYZInterpolation and: // Eats a floating point number, then - // Re-runs the read function 3 more times, with force enabled so that the previous values aren't cleared. + // Re-runs the read function 3 more times. // When it does that it's reading in a bunch of sLinearInterpolation keys, not sXYZInterpolation. else if(mInterpolationType == sXYZInterpolation) { diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index b18a88d14..1d1e1a22d 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -442,6 +442,9 @@ public: { private: const Nif::QuaternionKeyMap* mRotations; + const Nif::FloatKeyMap* mXRotations; + const Nif::FloatKeyMap* mYRotations; + const Nif::FloatKeyMap* mZRotations; const Nif::Vector3KeyMap* mTranslations; const Nif::FloatKeyMap* mScales; Nif::NIFFilePtr mNif; // Hold a SharedPtr to make sure key lists stay valid @@ -472,11 +475,25 @@ public: return keys.rbegin()->second.mValue; } + Ogre::Quaternion getXYZRotation(float time) const + { + float xrot = interpKey(mXRotations->mKeys, time); + float yrot = interpKey(mYRotations->mKeys, time); + float zrot = interpKey(mZRotations->mKeys, time); + Ogre::Quaternion xr(Ogre::Radian(xrot), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr(Ogre::Radian(yrot), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr(Ogre::Radian(zrot), Ogre::Vector3::UNIT_Z); + return (xr*yr*zr); + } + public: /// @note The NiKeyFrameData must be valid as long as this KeyframeController exists. Value(Ogre::Node *target, const Nif::NIFFilePtr& nif, const Nif::NiKeyframeData *data) : NodeTargetValue(target) , mRotations(&data->mRotations) + , mXRotations(&data->mXRotations) + , mYRotations(&data->mYRotations) + , mZRotations(&data->mZRotations) , mTranslations(&data->mTranslations) , mScales(&data->mScales) , mNif(nif) @@ -486,6 +503,8 @@ public: { if(mRotations->mKeys.size() > 0) return interpKey(mRotations->mKeys, time); + else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + return getXYZRotation(time); return mNode->getOrientation(); } @@ -513,6 +532,8 @@ public: { if(mRotations->mKeys.size() > 0) mNode->setOrientation(interpKey(mRotations->mKeys, time)); + else if (!mXRotations->mKeys.empty() || !mYRotations->mKeys.empty() || !mZRotations->mKeys.empty()) + mNode->setOrientation(getXYZRotation(time)); if(mTranslations->mKeys.size() > 0) mNode->setPosition(interpKey(mTranslations->mKeys, time)); if(mScales->mKeys.size() > 0) From e313ed3cefea5c41865d4d3d45f6abf8f9564312 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Dec 2014 20:58:33 +0100 Subject: [PATCH 81/98] Support animated container models --- apps/openmw/mwclass/container.cpp | 7 +++++-- apps/openmw/mwrender/activatoranimation.cpp | 13 ++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 179070aed..59e51e461 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -7,6 +7,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/failedaction.hpp" @@ -21,7 +22,7 @@ #include "../mwgui/tooltips.hpp" -#include "../mwrender/objects.hpp" +#include "../mwrender/actors.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwmechanics/npcstats.hpp" @@ -87,7 +88,8 @@ namespace MWClass { const std::string model = getModel(ptr); if (!model.empty()) { - renderingInterface.getObjects().insertModel(ptr, model); + MWRender::Actors& actors = renderingInterface.getActors(); + actors.insertActivator(ptr); } } @@ -96,6 +98,7 @@ namespace MWClass const std::string model = getModel(ptr); if(!model.empty()) physics.addObject(ptr); + MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Container::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index de0457e57..540876a3e 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -4,6 +4,8 @@ #include "../mwbase/world.hpp" +#include "../mwworld/class.hpp" + #include "renderconst.hpp" namespace MWRender @@ -16,17 +18,14 @@ ActivatorAnimation::~ActivatorAnimation() ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) : Animation(ptr, ptr.getRefData().getBaseNode()) { - MWWorld::LiveCellRef *ref = mPtr.get(); + const std::string& model = mPtr.getClass().getModel(mPtr); - assert(ref->mBase != NULL); - if(!ref->mBase->mModel.empty()) + if(!model.empty()) { - const std::string name = "meshes\\"+ref->mBase->mModel; - - setObjectRoot(name, false); + setObjectRoot(model, false); setRenderProperties(mObjectRoot, RV_Misc, RQG_Main, RQG_Alpha); - addAnimSource(name); + addAnimSource(model); } } From 416d549568789db9eef0ff11278f6052b2530794 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Dec 2014 22:02:18 +0100 Subject: [PATCH 82/98] Fix animation glitch caused by knockdown If the player was knocked down while having no weapon, spell nor fists ready, the animation state would incorrectly shift to "weapon equipped" even though no weapon is equipped. --- apps/openmw/mwmechanics/character.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2e4f76c1a..46e06f460 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1072,7 +1072,8 @@ bool CharacterController::updateWeaponState() } else if (mHitState == CharState_KnockDown) { - mUpperBodyState = UpperCharState_WeapEquiped; + if (mUpperBodyState > UpperCharState_WeapEquiped) + mUpperBodyState = UpperCharState_WeapEquiped; mAnimation->disable(mCurrentWeapon); } } From 3f0bc6eecbef10d63fc54a3282c3b61823fd008f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Dec 2014 23:36:06 +0100 Subject: [PATCH 83/98] Ignore extra bytes after the SCVR string list (Fixes #2184) --- components/esm/loadscpt.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index 19e3f3bb3..07561c2ea 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -30,7 +30,14 @@ void Script::load(ESMReader &esm) int s = mData.mStringTableSize; std::vector tmp (s); - esm.getHExact (&tmp[0], s); + // not using getHExact, vanilla doesn't seem to mind unused bytes at the end + esm.getSubHeader(); + int left = esm.getSubSize(); + if (left < s) + esm.fail("SCVR string list is smaller than specified"); + esm.getExact(&tmp[0], s); + if (left > s) + esm.skip(left-s); // skip the leftover junk // Set up the list of variable names mVarNames.resize(mData.mNumShorts + mData.mNumLongs + mData.mNumFloats); From 7c59ea629694fde2322d0c6b7082e1e6f5642a7b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Dec 2014 13:01:55 +0100 Subject: [PATCH 84/98] added specialised report table --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/tools/reportsubview.cpp | 36 ++++------------ apps/opencs/view/tools/reportsubview.hpp | 23 ++-------- apps/opencs/view/tools/reporttable.cpp | 53 ++++++++++++++++++++++++ apps/opencs/view/tools/reporttable.hpp | 44 ++++++++++++++++++++ 5 files changed, 108 insertions(+), 50 deletions(-) create mode 100644 apps/opencs/view/tools/reporttable.cpp create mode 100644 apps/opencs/view/tools/reporttable.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bdfefbb83..fcc549002 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -92,7 +92,7 @@ opencs_hdrs_noqt (view/render opencs_units (view/tools - reportsubview + reportsubview reporttable ) opencs_units_noqt (view/tools diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index 5a2523789..df1a5298c 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -1,31 +1,15 @@ #include "reportsubview.hpp" -#include -#include - -#include "../../model/tools/reportmodel.hpp" - -#include "../../view/world/idtypedelegate.hpp" +#include "reporttable.hpp" CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) -: CSVDoc::SubView (id), mModel (document.getReport (id)) +: CSVDoc::SubView (id) { - setWidget (mTable = new QTableView (this)); - mTable->setModel (mModel); + setWidget (mTable = new ReportTable (document, id, this)); - mTable->horizontalHeader()->setResizeMode (QHeaderView::Interactive); - mTable->verticalHeader()->hide(); - mTable->setSortingEnabled (true); - mTable->setSelectionBehavior (QAbstractItemView::SelectRows); - mTable->setSelectionMode (QAbstractItemView::ExtendedSelection); - - mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate ( - document, this); - - mTable->setItemDelegateForColumn (0, mIdTypeDelegate); - - connect (mTable, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&))); + connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), + SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); } void CSVTools::ReportSubView::setEditLock (bool locked) @@ -33,13 +17,7 @@ void CSVTools::ReportSubView::setEditLock (bool locked) // ignored. We don't change document state anyway. } -void CSVTools::ReportSubView::updateUserSetting - (const QString &name, const QStringList &list) +void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStringList &list) { - mIdTypeDelegate->updateUserSetting (name, list); -} - -void CSVTools::ReportSubView::show (const QModelIndex& index) -{ - focusId (mModel->getUniversalId (index.row()), ""); + mTable->updateUserSetting (name, list); } diff --git a/apps/opencs/view/tools/reportsubview.hpp b/apps/opencs/view/tools/reportsubview.hpp index 9f6a4c1da..7e8a08e3c 100644 --- a/apps/opencs/view/tools/reportsubview.hpp +++ b/apps/opencs/view/tools/reportsubview.hpp @@ -11,27 +11,15 @@ namespace CSMDoc class Document; } -namespace CSMTools -{ - class ReportModel; -} - -namespace CSVWorld -{ - class CommandDelegate; -} - namespace CSVTools { - class Table; + class ReportTable; class ReportSubView : public CSVDoc::SubView { Q_OBJECT - CSMTools::ReportModel *mModel; - QTableView *mTable; - CSVWorld::CommandDelegate *mIdTypeDelegate; + ReportTable *mTable; public: @@ -39,12 +27,7 @@ namespace CSVTools virtual void setEditLock (bool locked); - virtual void updateUserSetting - (const QString &, const QStringList &); - - private slots: - - void show (const QModelIndex& index); + virtual void updateUserSetting (const QString &, const QStringList &); }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp new file mode 100644 index 000000000..cc0ced57f --- /dev/null +++ b/apps/opencs/view/tools/reporttable.cpp @@ -0,0 +1,53 @@ + +#include "reporttable.hpp" + +#include + +#include "../../model/tools/reportmodel.hpp" + +#include "../../view/world/idtypedelegate.hpp" + +CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, + const CSMWorld::UniversalId& id, QWidget *parent) +: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) +{ + horizontalHeader()->setResizeMode (QHeaderView::Interactive); + verticalHeader()->hide(); + setSortingEnabled (true); + setSelectionBehavior (QAbstractItemView::SelectRows); + setSelectionMode (QAbstractItemView::ExtendedSelection); + + setModel (mModel); + + mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate ( + document, this); + + setItemDelegateForColumn (0, mIdTypeDelegate); + + connect (this, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&))); +} + +std::vector CSVTools::ReportTable::getDraggedRecords() const +{ + std::vector ids; + + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); + ++iter) + { + ids.push_back (mModel->getUniversalId (iter->row())); + } + + return ids; +} + +void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list) +{ + mIdTypeDelegate->updateUserSetting (name, list); +} + +void CSVTools::ReportTable::show (const QModelIndex& index) +{ + emit editRequest (mModel->getUniversalId (index.row()), ""); +} \ No newline at end of file diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp new file mode 100644 index 000000000..18365f58e --- /dev/null +++ b/apps/opencs/view/tools/reporttable.hpp @@ -0,0 +1,44 @@ +#ifndef CSV_TOOLS_REPORTTABLE_H +#define CSV_TOOLS_REPORTTABLE_H + +#include "../world/dragrecordtable.hpp" + +namespace CSMTools +{ + class ReportModel; +} + +namespace CSVWorld +{ + class CommandDelegate; +} + +namespace CSVTools +{ + class ReportTable : public CSVWorld::DragRecordTable + { + Q_OBJECT + + CSMTools::ReportModel *mModel; + CSVWorld::CommandDelegate *mIdTypeDelegate; + + public: + + ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, + QWidget *parent = 0); + + virtual std::vector getDraggedRecords() const; + + void updateUserSetting (const QString& name, const QStringList& list); + + private slots: + + void show (const QModelIndex& index); + + signals: + + void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); + }; +} + +#endif From 6c18a3b0b5d1fecb102eee68dbbeed441c4e6e99 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Dec 2014 13:19:43 +0100 Subject: [PATCH 85/98] allow drags from report table --- apps/opencs/view/tools/reporttable.cpp | 6 ++++++ apps/opencs/view/tools/reporttable.hpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index cc0ced57f..e4acc2629 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -7,6 +7,12 @@ #include "../../view/world/idtypedelegate.hpp" +void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event) +{ + if (event->buttons() & Qt::LeftButton) + startDrag (*this); +} + CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, QWidget *parent) : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 18365f58e..acd1ed3cc 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -22,6 +22,10 @@ namespace CSVTools CSMTools::ReportModel *mModel; CSVWorld::CommandDelegate *mIdTypeDelegate; + private: + + void mouseMoveEvent (QMouseEvent *event); + public: ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, From 350b0cb93c7315dd3015b2688a500f7470644c88 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Dec 2014 13:45:47 +0100 Subject: [PATCH 86/98] added hidden hint column to report model --- apps/opencs/model/tools/reportmodel.cpp | 27 +++++++++++++++++++------ apps/opencs/model/tools/reportmodel.hpp | 7 +++++-- apps/opencs/view/tools/reporttable.cpp | 3 ++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 75545a7c7..135420612 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -16,7 +16,7 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const if (parent.isValid()) return 0; - return 2; + return 3; } QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const @@ -26,8 +26,11 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const if (index.column()==0) return static_cast (mRows.at (index.row()).first.getType()); - else - return mRows.at (index.row()).second.c_str(); + + if (index.column()==1) + return QString::fromUtf8 (mRows.at (index.row()).second.first.c_str()); + + return QString::fromUtf8 (mRows.at (index.row()).second.second.c_str()); } QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orientation, int role) const @@ -38,7 +41,13 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta if (orientation==Qt::Vertical) return QVariant(); - return tr (section==0 ? "Type" : "Description"); + if (section==0) + return "Type"; + + if (section==1) + return "Description"; + + return "Hint"; } bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& parent) @@ -51,11 +60,12 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p return true; } -void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message) +void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint) { beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); - mRows.push_back (std::make_pair (id, message)); + mRows.push_back (std::make_pair (id, std::make_pair (message, hint))); endInsertRows(); } @@ -64,3 +74,8 @@ const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) con { return mRows.at (row).first; } + +std::string CSMTools::ReportModel::getHint (int row) const +{ + return mRows.at (row).second.second; +} \ No newline at end of file diff --git a/apps/opencs/model/tools/reportmodel.hpp b/apps/opencs/model/tools/reportmodel.hpp index 0f000245e..709e024a7 100644 --- a/apps/opencs/model/tools/reportmodel.hpp +++ b/apps/opencs/model/tools/reportmodel.hpp @@ -14,7 +14,7 @@ namespace CSMTools { Q_OBJECT - std::vector > mRows; + std::vector > > mRows; public: @@ -28,9 +28,12 @@ namespace CSMTools virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); - void add (const CSMWorld::UniversalId& id, const std::string& message); + void add (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint = ""); const CSMWorld::UniversalId& getUniversalId (int row) const; + + std::string getHint (int row) const; }; } diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index e4acc2629..5bf38f020 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -24,6 +24,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setSelectionMode (QAbstractItemView::ExtendedSelection); setModel (mModel); + setColumnHidden (2, true); mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate ( document, this); @@ -55,5 +56,5 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin void CSVTools::ReportTable::show (const QModelIndex& index) { - emit editRequest (mModel->getUniversalId (index.row()), ""); + emit editRequest (mModel->getUniversalId (index.row()), mModel->getHint (index.row())); } \ No newline at end of file From f2fc6933250d4cfa6b4a1459463657a349e00f76 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Dec 2014 14:17:56 +0100 Subject: [PATCH 87/98] added context menu to report table --- apps/opencs/view/tools/reporttable.cpp | 28 ++++++++++++++++++++++++++ apps/opencs/view/tools/reporttable.hpp | 7 +++++++ 2 files changed, 35 insertions(+) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 5bf38f020..ec2ba74d2 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -2,11 +2,26 @@ #include "reporttable.hpp" #include +#include +#include #include "../../model/tools/reportmodel.hpp" #include "../../view/world/idtypedelegate.hpp" +void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + // create context menu + QMenu menu (this); + + if (!selectedRows.empty()) + menu.addAction (mShowAction); + + menu.exec (event->globalPos()); +} + void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) @@ -31,6 +46,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setItemDelegateForColumn (0, mIdTypeDelegate); + mShowAction = new QAction (tr ("Show"), this); + connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection())); + addAction (mShowAction); + connect (this, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&))); } @@ -57,4 +76,13 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin void CSVTools::ReportTable::show (const QModelIndex& index) { emit editRequest (mModel->getUniversalId (index.row()), mModel->getHint (index.row())); +} + +void CSVTools::ReportTable::showSelection() +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); + ++iter) + show (*iter); } \ No newline at end of file diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index acd1ed3cc..75b6e8553 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -3,6 +3,8 @@ #include "../world/dragrecordtable.hpp" +class QAction; + namespace CSMTools { class ReportModel; @@ -21,9 +23,12 @@ namespace CSVTools CSMTools::ReportModel *mModel; CSVWorld::CommandDelegate *mIdTypeDelegate; + QAction *mShowAction; private: + void contextMenuEvent (QContextMenuEvent *event); + void mouseMoveEvent (QMouseEvent *event); public: @@ -39,6 +44,8 @@ namespace CSVTools void show (const QModelIndex& index); + void showSelection(); + signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); From 58f4cc882fdf80f46c4965d321f23d9f145058fa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Dec 2014 14:30:40 +0100 Subject: [PATCH 88/98] added remove action to report table context menu --- apps/opencs/view/tools/reporttable.cpp | 22 ++++++++++++++++++++++ apps/opencs/view/tools/reporttable.hpp | 3 +++ 2 files changed, 25 insertions(+) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index ec2ba74d2..eee1da35f 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -1,6 +1,8 @@ #include "reporttable.hpp" +#include + #include #include #include @@ -17,7 +19,10 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) QMenu menu (this); if (!selectedRows.empty()) + { menu.addAction (mShowAction); + menu.addAction (mRemoveAction); + } menu.exec (event->globalPos()); } @@ -50,6 +55,10 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection())); addAction (mShowAction); + mRemoveAction = new QAction (tr ("Remove from list"), this); + connect (mRemoveAction, SIGNAL (triggered()), this, SLOT (removeSelection())); + addAction (mRemoveAction); + connect (this, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&))); } @@ -85,4 +94,17 @@ void CSVTools::ReportTable::showSelection() for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) show (*iter); +} + +void CSVTools::ReportTable::removeSelection() +{ + QModelIndexList selectedRows = selectionModel()->selectedRows(); + + std::reverse (selectedRows.begin(), selectedRows.end()); + + for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); + ++iter) + mModel->removeRows (iter->row(), 1); + + selectionModel()->clear(); } \ No newline at end of file diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 75b6e8553..2f53425d4 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -24,6 +24,7 @@ namespace CSVTools CSMTools::ReportModel *mModel; CSVWorld::CommandDelegate *mIdTypeDelegate; QAction *mShowAction; + QAction *mRemoveAction; private: @@ -46,6 +47,8 @@ namespace CSVTools void showSelection(); + void removeSelection(); + signals: void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); From 6a67aba33655539c2bed83af06e269557473b7a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Dec 2014 15:08:51 +0100 Subject: [PATCH 89/98] added double click with modifier actions in report table --- apps/opencs/view/tools/reporttable.cpp | 42 +++++++++++++++++++++----- apps/opencs/view/tools/reporttable.hpp | 4 +-- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index eee1da35f..4cd11925e 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -33,6 +33,39 @@ void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event) startDrag (*this); } +void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) +{ + Qt::KeyboardModifiers modifiers = + event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier); + + QModelIndex index = currentIndex(); + + selectionModel()->select (index, + QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows); + + switch (modifiers) + { + case 0: + + event->accept(); + showSelection(); + break; + + case Qt::ShiftModifier: + + event->accept(); + removeSelection(); + break; + + case Qt::ControlModifier: + + event->accept(); + showSelection(); + removeSelection(); + break; + } +} + CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, QWidget *parent) : CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) @@ -58,8 +91,6 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, mRemoveAction = new QAction (tr ("Remove from list"), this); connect (mRemoveAction, SIGNAL (triggered()), this, SLOT (removeSelection())); addAction (mRemoveAction); - - connect (this, SIGNAL (doubleClicked (const QModelIndex&)), this, SLOT (show (const QModelIndex&))); } std::vector CSVTools::ReportTable::getDraggedRecords() const @@ -82,18 +113,13 @@ void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStrin mIdTypeDelegate->updateUserSetting (name, list); } -void CSVTools::ReportTable::show (const QModelIndex& index) -{ - emit editRequest (mModel->getUniversalId (index.row()), mModel->getHint (index.row())); -} - void CSVTools::ReportTable::showSelection() { QModelIndexList selectedRows = selectionModel()->selectedRows(); for (QModelIndexList::const_iterator iter (selectedRows.begin()); iter!=selectedRows.end(); ++iter) - show (*iter); + emit editRequest (mModel->getUniversalId (iter->row()), mModel->getHint (iter->row())); } void CSVTools::ReportTable::removeSelection() diff --git a/apps/opencs/view/tools/reporttable.hpp b/apps/opencs/view/tools/reporttable.hpp index 2f53425d4..7a5b232f9 100644 --- a/apps/opencs/view/tools/reporttable.hpp +++ b/apps/opencs/view/tools/reporttable.hpp @@ -32,6 +32,8 @@ namespace CSVTools void mouseMoveEvent (QMouseEvent *event); + virtual void mouseDoubleClickEvent (QMouseEvent *event); + public: ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, @@ -43,8 +45,6 @@ namespace CSVTools private slots: - void show (const QModelIndex& index); - void showSelection(); void removeSelection(); From 9a1b7cbe52c082c923d19bfdd87e623cbb70db27 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Dec 2014 16:50:09 +0100 Subject: [PATCH 90/98] Add SharedStateButton, used in spell window and controls box to apply mouseover effect to all buttons within one row (Fixes #1986) --- apps/openmw/mwgui/settingswindow.cpp | 11 +- apps/openmw/mwgui/spellwindow.cpp | 42 +++++--- components/CMakeLists.txt | 2 +- components/widgets/sharedstatebutton.cpp | 128 +++++++++++++++++++++++ components/widgets/sharedstatebutton.hpp | 51 +++++++++ components/widgets/widgets.cpp | 2 + 6 files changed, 221 insertions(+), 15 deletions(-) create mode 100644 components/widgets/sharedstatebutton.cpp create mode 100644 components/widgets/sharedstatebutton.hpp diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 948423a35..8ef0a331a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -9,6 +9,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" @@ -454,16 +456,21 @@ namespace MWGui std::string binding = MWBase::Environment::get().getInputManager()->getActionBindingName (*it); - MyGUI::TextBox* leftText = mControlsBox->createWidget("SandText", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); + Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); - MyGUI::Button* rightText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); + Gui::SharedStateButton* rightText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); rightText->setCaptionWithReplacing(binding); rightText->setTextAlign (MyGUI::Align::Right); rightText->setUserData(*it); // save the action id for callbacks rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction); rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel); curH += h; + + Gui::ButtonGroup group; + group.push_back(leftText); + group.push_back(rightText); + Gui::SharedStateButton::createButtonGroup(group); } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 97ebbcde2..7904c249a 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -177,7 +179,7 @@ namespace MWGui for (std::vector::const_iterator it = spellList.begin(); it != spellList.end(); ++it) { const ESM::Spell* spell = esmStore.get().find(*it); - MyGUI::Button* t = mSpellView->createWidget("SandTextButton", + Gui::SharedStateButton* t = mSpellView->createWidget("SandTextButton", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); t->setCaption(spell->mName); t->setTextAlign(MyGUI::Align::Left); @@ -185,20 +187,28 @@ namespace MWGui t->setUserString("Spell", *it); t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); - t->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell()); // cost / success chance - MyGUI::Button* costChance = mSpellView->createWidget("SandTextButton", + Gui::SharedStateButton* costChance = mSpellView->createWidget("SandTextButton", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); std::string cost = boost::lexical_cast(spell->mData.mCost); std::string chance = boost::lexical_cast(int(MWMechanics::getSpellSuccessChance(*it, player))); costChance->setCaption(cost + "/" + chance); costChance->setTextAlign(MyGUI::Align::Right); - costChance->setNeedMouseFocus(false); - costChance->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell()); + costChance->setUserString("ToolTipType", "Spell"); + costChance->setUserString("Spell", *it); + costChance->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); + costChance->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); t->setSize(mWidth-12-costChance->getTextSize().width, t->getHeight()); + Gui::ButtonGroup group; + group.push_back(t); + group.push_back(costChance); + Gui::SharedStateButton::createButtonGroup(group); + + t->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell()); + mHeight += spellHeight; } @@ -224,7 +234,7 @@ namespace MWGui } } - MyGUI::Button* t = mSpellView->createWidget(equipped ? "SandTextButton" : "SpellTextUnequipped", + Gui::SharedStateButton* t = mSpellView->createWidget(equipped ? "SandTextButton" : "SpellTextUnequipped", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); t->setCaption(item.getClass().getName(item)); t->setTextAlign(MyGUI::Align::Left); @@ -233,12 +243,9 @@ namespace MWGui t->setUserString("Equipped", equipped ? "true" : "false"); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected); t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); - if (store.getSelectedEnchantItem() != store.end()) - t->setStateSelected(item == *store.getSelectedEnchantItem()); - // cost / charge - MyGUI::Button* costCharge = mSpellView->createWidget(equipped ? "SandTextButton" : "SpellTextUnequipped", + Gui::SharedStateButton* costCharge = mSpellView->createWidget(equipped ? "SandTextButton" : "SpellTextUnequipped", MyGUI::IntCoord(4, mHeight, mWidth-8, spellHeight), MyGUI::Align::Left | MyGUI::Align::Top); float enchantCost = enchant->mData.mCost; @@ -257,11 +264,22 @@ namespace MWGui charge = "100"; } + + costCharge->setUserData(item); + costCharge->setUserString("ToolTipType", "ItemPtr"); + costCharge->setUserString("Equipped", equipped ? "true" : "false"); + costCharge->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected); + costCharge->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); costCharge->setCaption(cost + "/" + charge); costCharge->setTextAlign(MyGUI::Align::Right); - costCharge->setNeedMouseFocus(false); + + Gui::ButtonGroup group; + group.push_back(t); + group.push_back(costCharge); + Gui::SharedStateButton::createButtonGroup(group); + if (store.getSelectedEnchantItem() != store.end()) - costCharge->setStateSelected(item == *store.getSelectedEnchantItem()); + t->setStateSelected(item == *store.getSelectedEnchantItem()); t->setSize(mWidth-12-costCharge->getTextSize().width, t->getHeight()); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6a1db371d..234325718 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -96,7 +96,7 @@ add_component_dir (ogreinit ) add_component_dir (widgets - box imagebutton tags list numericeditbox widgets + box imagebutton tags list numericeditbox sharedstatebutton widgets ) add_component_dir (fontloader diff --git a/components/widgets/sharedstatebutton.cpp b/components/widgets/sharedstatebutton.cpp new file mode 100644 index 000000000..6859a3065 --- /dev/null +++ b/components/widgets/sharedstatebutton.cpp @@ -0,0 +1,128 @@ +#include "sharedstatebutton.hpp" + +namespace Gui +{ + + SharedStateButton::SharedStateButton() + : mIsMousePressed(false) + , mIsMouseFocus(false) + { + + } + + void SharedStateButton::shutdownOverride() + { + ButtonGroup group = mSharedWith; // make a copy so that we don't nuke the vector during iteration + for (ButtonGroup::iterator it = group.begin(); it != group.end(); ++it) + { + (*it)->shareStateWith(ButtonGroup()); + } + } + + void SharedStateButton::shareStateWith(ButtonGroup shared) + { + mSharedWith = shared; + } + + void SharedStateButton::onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id) + { + mIsMousePressed = true; + Base::onMouseButtonPressed(_left, _top, _id); + updateButtonState(); + } + + void SharedStateButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) + { + mIsMousePressed = false; + Base::onMouseButtonReleased(_left, _top, _id); + updateButtonState(); + } + + void SharedStateButton::onMouseSetFocus(MyGUI::Widget *_old) + { + mIsMouseFocus = true; + Base::onMouseSetFocus(_old); + updateButtonState(); + } + + void SharedStateButton::onMouseLostFocus(MyGUI::Widget *_new) + { + mIsMouseFocus = false; + Base::onMouseLostFocus(_new); + updateButtonState(); + } + + void SharedStateButton::baseUpdateEnable() + { + Base::baseUpdateEnable(); + updateButtonState(); + } + + void SharedStateButton::setStateSelected(bool _value) + { + Base::setStateSelected(_value); + updateButtonState(); + + for (ButtonGroup::iterator it = mSharedWith.begin(); it != mSharedWith.end(); ++it) + { + (*it)->MyGUI::Button::setStateSelected(getStateSelected()); + } + } + + bool SharedStateButton::_setState(const std::string &_value) + { + bool ret = _setWidgetState(_value); + if (ret) + { + for (ButtonGroup::iterator it = mSharedWith.begin(); it != mSharedWith.end(); ++it) + { + (*it)->_setWidgetState(_value); + } + } + return ret; + } + + void SharedStateButton::updateButtonState() + { + if (getStateSelected()) + { + if (!getInheritedEnabled()) + { + if (!_setState("disabled_checked")) + _setState("disabled"); + } + else if (mIsMousePressed) + { + if (!_setState("pushed_checked")) + _setState("pushed"); + } + else if (mIsMouseFocus) + { + if (!_setState("highlighted_checked")) + _setState("pushed"); + } + else + _setState("normal_checked"); + } + else + { + if (!getInheritedEnabled()) + _setState("disabled"); + else if (mIsMousePressed) + _setState("pushed"); + else if (mIsMouseFocus) + _setState("highlighted"); + else + _setState("normal"); + } + } + + void SharedStateButton::createButtonGroup(ButtonGroup group) + { + for (ButtonGroup::iterator it = group.begin(); it != group.end(); ++it) + { + (*it)->shareStateWith(group); + } + } + +} diff --git a/components/widgets/sharedstatebutton.hpp b/components/widgets/sharedstatebutton.hpp new file mode 100644 index 000000000..3d7fbc84e --- /dev/null +++ b/components/widgets/sharedstatebutton.hpp @@ -0,0 +1,51 @@ +#ifndef OPENMW_WIDGETS_SHAREDSTATEBUTTON_HPP +#define OPENMW_WIDGETS_SHAREDSTATEBUTTON_HPP + +#include + +namespace Gui +{ + + class SharedStateButton; + + typedef std::vector ButtonGroup; + + /// @brief A button that applies its own state changes to other widgets, to do this you define it as part of a ButtonGroup. + class SharedStateButton : public MyGUI::Button + { + MYGUI_RTTI_DERIVED(SharedStateButton) + + public: + SharedStateButton(); + + protected: + void updateButtonState(); + + virtual void onMouseButtonPressed(int _left, int _top, MyGUI::MouseButton _id); + virtual void onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id); + virtual void onMouseSetFocus(MyGUI::Widget* _old); + virtual void onMouseLostFocus(MyGUI::Widget* _new); + virtual void baseUpdateEnable(); + + virtual void shutdownOverride(); + + bool _setState(const std::string &_value); + + public: + void shareStateWith(ButtonGroup shared); + + /// @note The ButtonGroup connection will be destroyed when any widget in the group gets destroyed. + static void createButtonGroup(ButtonGroup group); + + //! Set button selected state + void setStateSelected(bool _value); + + private: + ButtonGroup mSharedWith; + + bool mIsMousePressed; + bool mIsMouseFocus; + }; +} + +#endif diff --git a/components/widgets/widgets.cpp b/components/widgets/widgets.cpp index b35dc88a4..82839c6c9 100644 --- a/components/widgets/widgets.cpp +++ b/components/widgets/widgets.cpp @@ -6,6 +6,7 @@ #include "numericeditbox.hpp" #include "box.hpp" #include "imagebutton.hpp" +#include "sharedstatebutton.hpp" namespace Gui { @@ -20,6 +21,7 @@ namespace Gui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); } } From 41542dedf7686bd222aa99df4270fc5b3f20e928 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Dec 2014 17:24:05 +0100 Subject: [PATCH 91/98] Fix map insert return value mixup (Fixes #2192) --- apps/openmw/mwworld/store.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 5966a99b9..c8fa087c2 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -859,16 +859,16 @@ namespace MWWorld // Try to overwrite existing record if (!pathgrid.mCell.empty()) { - std::pair found = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); - if (found.second) - found.first->second = pathgrid; + std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; } else { - std::pair found = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), + std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); - if (found.second) - found.first->second = pathgrid; + if (!ret.second) + ret.first->second = pathgrid; } } @@ -953,9 +953,9 @@ namespace MWWorld record.load(esm); // Try to overwrite existing record - std::pair found = mStatic.insert(std::make_pair(record.mIndex, record)); - if (found.second) - found.first->second = record; + std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); + if (!ret.second) + ret.first->second = record; } int getSize() const { From 2952a0e2aa7d9fa58bc37c5f235a61f28afd6a29 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Dec 2014 19:53:24 +0100 Subject: [PATCH 92/98] Make Resurrect function reset most of the runtime state (Fixes #2181) --- apps/openmw/mwscript/statsextensions.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index d5647db10..63405e5b8 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1179,7 +1179,14 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - ptr.getClass().getCreatureStats(ptr).resurrect(); + + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + ptr.getClass().getCreatureStats(ptr).resurrect(); + else if (ptr.getClass().getCreatureStats(ptr).isDead()) + { + // resets runtime state such as inventory, stats and AI. does not reset position in the world + ptr.getRefData().setCustomData(NULL); + } } }; From f49fde3d5de464c546aa41e69172c5063cf600dd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Dec 2014 21:08:18 +0100 Subject: [PATCH 93/98] Add support for undeleting references (Fixes #2193) Deleted references should be accessible via an explicit reference, and can be undeleted using "setdelete 0". Also the Resurrect function implicitely undeletes the given reference. --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwscript/miscextensions.cpp | 4 ++++ apps/openmw/mwscript/statsextensions.cpp | 1 + apps/openmw/mwworld/cellreflist.hpp | 4 ++-- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/refdata.cpp | 5 +++++ apps/openmw/mwworld/refdata.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 19 +++++++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 1 + 9 files changed, 36 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index c1a889913..2dd135f3d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -279,6 +279,7 @@ namespace MWBase ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; + virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index aa80213de..ec2048e11 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -571,6 +571,10 @@ namespace MWScript if (parameter == 1) MWBase::Environment::get().getWorld()->deleteObject(ptr); + else if (parameter == 0) + MWBase::Environment::get().getWorld()->undeleteObject(ptr); + else + throw std::runtime_error("SetDelete: unexpected parameter"); } }; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 63405e5b8..09ab0183c 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1184,6 +1184,7 @@ namespace MWScript ptr.getClass().getCreatureStats(ptr).resurrect(); else if (ptr.getClass().getCreatureStats(ptr).isDead()) { + MWBase::Environment::get().getWorld()->undeleteObject(ptr); // resets runtime state such as inventory, stats and AI. does not reset position in the world ptr.getRefData().setCustomData(NULL); } diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 9c3370f08..cf1289654 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -27,7 +27,7 @@ namespace MWWorld LiveRef *find (const std::string& name) { for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (iter->mData.getCount() > 0 && iter->mRef.getRefId() == name) + if (iter->mRef.getRefId() == name) return &*iter; return 0; @@ -42,7 +42,7 @@ namespace MWWorld LiveCellRef *searchViaHandle (const std::string& handle) { for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (iter->mData.getCount()>0 && iter->mData.getBaseNode() && + if (iter->mData.getBaseNode() && iter->mData.getHandle()==handle) return &*iter; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 05e7b0b2e..eba627b3e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -196,7 +196,7 @@ namespace MWWorld for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { - if (iter->mData.isDeleted()) + if (iter->mData.isDeletedByContentFile()) continue; if (!functor (MWWorld::Ptr(&*iter, this))) return false; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 78fea2b86..c2a5e5f83 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -180,6 +180,11 @@ namespace MWWorld return mDeleted || mCount == 0; } + bool RefData::isDeletedByContentFile() const + { + return mDeleted; + } + MWScript::Locals& RefData::getLocals() { return mLocals; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 1ed3cd79d..da7986ba0 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -100,6 +100,8 @@ namespace MWWorld /// Returns true if the object was either deleted by the content file or by gameplay. bool isDeleted() const; + /// Returns true if the object was deleted by a content file. + bool isDeletedByContentFile() const; MWScript::Locals& getLocals(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7baf1d3e5..d783857f1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1072,6 +1072,25 @@ namespace MWWorld } } + void World::undeleteObject(const Ptr& ptr) + { + if (ptr.getCellRef().getRefNum().mContentFile == -1) + return; + if (ptr.getRefData().isDeleted()) + { + ptr.getRefData().setCount(1); + if (mWorldScene->getActiveCells().find(ptr.getCell()) != mWorldScene->getActiveCells().end() + && ptr.getRefData().isEnabled()) + { + mWorldScene->addObjectToScene(ptr); + std::string script = ptr.getClass().getScript(ptr); + if (!script.empty()) + mLocalScripts.add(script, ptr); + addContainerScripts(ptr, ptr.getCell()); + } + } + } + void World::moveObject(const Ptr &ptr, CellStore* newCell, float x, float y, float z) { ESM::Position pos = ptr.getRefData().getPosition(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index fef279705..2da6a6e05 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -338,6 +338,7 @@ namespace MWWorld virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); virtual void deleteObject (const Ptr& ptr); + virtual void undeleteObject (const Ptr& ptr); virtual void moveObject (const Ptr& ptr, float x, float y, float z); virtual void moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z); From 109fbab54688a65c500937993f39e87ee2a1e798 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Dec 2014 16:02:28 +0100 Subject: [PATCH 94/98] changed column/row numbering in script compiler error messages from being starting at 0 to starting at 1 --- components/compiler/streamerrorhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/compiler/streamerrorhandler.cpp b/components/compiler/streamerrorhandler.cpp index 8a74ad086..fc1a05943 100644 --- a/components/compiler/streamerrorhandler.cpp +++ b/components/compiler/streamerrorhandler.cpp @@ -16,7 +16,7 @@ namespace Compiler mStream << "warning "; mStream - << "line " << loc.mLine << ", column " << loc.mColumn + << "line " << loc.mLine+1 << ", column " << loc.mColumn+1 << " (" << loc.mLiteral << ")" << std::endl << " " << message << std::endl; } From 3a847732b44048ab474330c7b6330974ce55b9a5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Dec 2014 18:57:47 +0100 Subject: [PATCH 95/98] abstracted message collection into a class --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/doc/loader.cpp | 8 +-- apps/opencs/model/doc/messages.cpp | 28 ++++++++++ apps/opencs/model/doc/messages.hpp | 44 +++++++++++++++ apps/opencs/model/doc/operation.cpp | 6 +-- apps/opencs/model/doc/stage.hpp | 4 +- apps/opencs/model/tools/birthsigncheck.cpp | 2 +- apps/opencs/model/tools/birthsigncheck.hpp | 2 +- apps/opencs/model/tools/bodypartcheck.cpp | 2 +- apps/opencs/model/tools/bodypartcheck.hpp | 2 +- apps/opencs/model/tools/classcheck.cpp | 2 +- apps/opencs/model/tools/classcheck.hpp | 2 +- apps/opencs/model/tools/factioncheck.cpp | 2 +- apps/opencs/model/tools/factioncheck.hpp | 2 +- apps/opencs/model/tools/mandatoryid.cpp | 5 +- apps/opencs/model/tools/mandatoryid.hpp | 2 +- apps/opencs/model/tools/racecheck.cpp | 6 +-- apps/opencs/model/tools/racecheck.hpp | 6 +-- .../opencs/model/tools/referenceablecheck.cpp | 54 +++++++++---------- .../opencs/model/tools/referenceablecheck.hpp | 54 +++++++++---------- apps/opencs/model/tools/regioncheck.cpp | 2 +- apps/opencs/model/tools/regioncheck.hpp | 2 +- apps/opencs/model/tools/scriptcheck.cpp | 2 +- apps/opencs/model/tools/scriptcheck.hpp | 4 +- apps/opencs/model/tools/skillcheck.cpp | 2 +- apps/opencs/model/tools/skillcheck.hpp | 2 +- apps/opencs/model/tools/soundcheck.cpp | 2 +- apps/opencs/model/tools/soundcheck.hpp | 2 +- apps/opencs/model/tools/spellcheck.cpp | 2 +- apps/opencs/model/tools/spellcheck.hpp | 2 +- apps/opencs/model/world/data.cpp | 13 +++-- apps/opencs/model/world/data.hpp | 2 +- apps/opencs/model/world/refcollection.cpp | 5 +- apps/opencs/model/world/refcollection.hpp | 2 +- 34 files changed, 174 insertions(+), 105 deletions(-) create mode 100644 apps/opencs/model/doc/messages.cpp create mode 100644 apps/opencs/model/doc/messages.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index fcc549002..468e172cd 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -11,7 +11,7 @@ opencs_units (model/doc ) opencs_units_noqt (model/doc - stage savingstate savingstages blacklist + stage savingstate savingstages blacklist messages ) opencs_hdrs_noqt (model/doc diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 712deb9df..43f3b850e 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -52,7 +52,7 @@ void CSMDoc::Loader::load() { if (iter->second.mRecordsLeft) { - CSMDoc::Stage::Messages messages; + CSMDoc::Messages messages; for (int i=0; igetData().continueLoading (messages)) { @@ -65,11 +65,11 @@ void CSMDoc::Loader::load() CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0); { // silence a g++ warning - for (CSMDoc::Stage::Messages::const_iterator iter (messages.begin()); + for (CSMDoc::Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter) { - document->getReport (log)->add (iter->first, iter->second); - emit loadMessage (document, iter->second); + document->getReport (log)->add (iter->mId, iter->mMessage); + emit loadMessage (document, iter->mMessage); } } diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp new file mode 100644 index 000000000..1fb423145 --- /dev/null +++ b/apps/opencs/model/doc/messages.cpp @@ -0,0 +1,28 @@ + +#include "messages.hpp" + +void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint) +{ + Message data; + data.mId = id; + data.mMessage = message; + data.mHint = hint; + + mMessages.push_back (data); +} + +void CSMDoc::Messages::push_back (const std::pair& data) +{ + add (data.first, data.second); +} + +CSMDoc::Messages::Iterator CSMDoc::Messages::begin() const +{ + return mMessages.begin(); +} + +CSMDoc::Messages::Iterator CSMDoc::Messages::end() const +{ + return mMessages.end(); +} \ No newline at end of file diff --git a/apps/opencs/model/doc/messages.hpp b/apps/opencs/model/doc/messages.hpp new file mode 100644 index 000000000..0f36c73a7 --- /dev/null +++ b/apps/opencs/model/doc/messages.hpp @@ -0,0 +1,44 @@ +#ifndef CSM_DOC_MESSAGES_H +#define CSM_DOC_MESSAGES_H + +#include +#include + +#include "../world/universalid.hpp" + +namespace CSMDoc +{ + class Messages + { + public: + + struct Message + { + CSMWorld::UniversalId mId; + std::string mMessage; + std::string mHint; + }; + + typedef std::vector Collection; + + typedef Collection::const_iterator Iterator; + + private: + + Collection mMessages; + + public: + + void add (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint = ""); + + /// \deprecated Use add instead. + void push_back (const std::pair& data); + + Iterator begin() const; + + Iterator end() const; + }; +} + +#endif diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 7f77e8ac9..a997579f8 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -84,7 +84,7 @@ void CSMDoc::Operation::abort() void CSMDoc::Operation::executeStage() { - Stage::Messages messages; + Messages messages; while (mCurrentStage!=mStages.end()) { @@ -112,8 +112,8 @@ void CSMDoc::Operation::executeStage() emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); - for (Stage::Messages::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter) - emit reportMessage (iter->first, iter->second, mType); + for (Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter) + emit reportMessage (iter->mId, iter->mMessage, mType); if (mCurrentStage==mStages.end()) exit(); diff --git a/apps/opencs/model/doc/stage.hpp b/apps/opencs/model/doc/stage.hpp index ca34c2229..126823ae9 100644 --- a/apps/opencs/model/doc/stage.hpp +++ b/apps/opencs/model/doc/stage.hpp @@ -6,14 +6,14 @@ #include "../world/universalid.hpp" +#include "messages.hpp" + namespace CSMDoc { class Stage { public: - typedef std::vector > Messages; - virtual ~Stage(); virtual int setup() = 0; diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index db20ce4bc..1d72e24b8 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -17,7 +17,7 @@ int CSMTools::BirthsignCheckStage::setup() return mBirthsigns.getSize(); } -void CSMTools::BirthsignCheckStage::perform (int stage, Messages& messages) +void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mBirthsigns.getRecord (stage); diff --git a/apps/opencs/model/tools/birthsigncheck.hpp b/apps/opencs/model/tools/birthsigncheck.hpp index 1030e5c02..16d4c666f 100644 --- a/apps/opencs/model/tools/birthsigncheck.hpp +++ b/apps/opencs/model/tools/birthsigncheck.hpp @@ -21,7 +21,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/bodypartcheck.cpp b/apps/opencs/model/tools/bodypartcheck.cpp index a26945acf..68a09485f 100644 --- a/apps/opencs/model/tools/bodypartcheck.cpp +++ b/apps/opencs/model/tools/bodypartcheck.cpp @@ -14,7 +14,7 @@ int CSMTools::BodyPartCheckStage::setup() return mBodyParts.getSize(); } -void CSMTools::BodyPartCheckStage::perform ( int stage, Messages &messages ) +void CSMTools::BodyPartCheckStage::perform (int stage, CSMDoc::Messages &messages) { const CSMWorld::Record &record = mBodyParts.getRecord(stage); diff --git a/apps/opencs/model/tools/bodypartcheck.hpp b/apps/opencs/model/tools/bodypartcheck.hpp index d72badfdf..0a6ca959a 100644 --- a/apps/opencs/model/tools/bodypartcheck.hpp +++ b/apps/opencs/model/tools/bodypartcheck.hpp @@ -27,7 +27,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform( int stage, Messages &messages ); + virtual void perform( int stage, CSMDoc::Messages &messages ); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index cea4f3a68..5b872a266 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -18,7 +18,7 @@ int CSMTools::ClassCheckStage::setup() return mClasses.getSize(); } -void CSMTools::ClassCheckStage::perform (int stage, Messages& messages) +void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mClasses.getRecord (stage); diff --git a/apps/opencs/model/tools/classcheck.hpp b/apps/opencs/model/tools/classcheck.hpp index ec50ba35d..b76da3f13 100644 --- a/apps/opencs/model/tools/classcheck.hpp +++ b/apps/opencs/model/tools/classcheck.hpp @@ -21,7 +21,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index ba8cfe1f9..0dfdee775 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -18,7 +18,7 @@ int CSMTools::FactionCheckStage::setup() return mFactions.getSize(); } -void CSMTools::FactionCheckStage::perform (int stage, Messages& messages) +void CSMTools::FactionCheckStage::perform (int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mFactions.getRecord (stage); diff --git a/apps/opencs/model/tools/factioncheck.hpp b/apps/opencs/model/tools/factioncheck.hpp index ccc44e6a9..321a4d6d8 100644 --- a/apps/opencs/model/tools/factioncheck.hpp +++ b/apps/opencs/model/tools/factioncheck.hpp @@ -21,7 +21,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 412e9f2f0..87d19401b 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -15,10 +15,9 @@ int CSMTools::MandatoryIdStage::setup() return mIds.size(); } -void CSMTools::MandatoryIdStage::perform (int stage, Messages& messages) +void CSMTools::MandatoryIdStage::perform (int stage, CSMDoc::Messages& messages) { if (mIdCollection.searchId (mIds.at (stage))==-1 || mIdCollection.getRecord (mIds.at (stage)).isDeleted()) - messages.push_back (std::make_pair (mCollectionId, - "Missing mandatory record: " + mIds.at (stage))); + messages.add (mCollectionId, "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 index a8afea62a..86015c982 100644 --- a/apps/opencs/model/tools/mandatoryid.hpp +++ b/apps/opencs/model/tools/mandatoryid.hpp @@ -30,7 +30,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 47aeda1e6..143d61772 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -7,7 +7,7 @@ #include "../world/universalid.hpp" -void CSMTools::RaceCheckStage::performPerRecord (int stage, Messages& messages) +void CSMTools::RaceCheckStage::performPerRecord (int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mRaces.getRecord (stage); @@ -46,7 +46,7 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, Messages& messages) /// \todo check data members that can't be edited in the table view } -void CSMTools::RaceCheckStage::performFinal (Messages& messages) +void CSMTools::RaceCheckStage::performFinal (CSMDoc::Messages& messages) { CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races); @@ -64,7 +64,7 @@ int CSMTools::RaceCheckStage::setup() return mRaces.getSize()+1; } -void CSMTools::RaceCheckStage::perform (int stage, Messages& messages) +void CSMTools::RaceCheckStage::perform (int stage, CSMDoc::Messages& messages) { if (stage==mRaces.getSize()) performFinal (messages); diff --git a/apps/opencs/model/tools/racecheck.hpp b/apps/opencs/model/tools/racecheck.hpp index c68b283be..3e67b7577 100644 --- a/apps/opencs/model/tools/racecheck.hpp +++ b/apps/opencs/model/tools/racecheck.hpp @@ -15,9 +15,9 @@ namespace CSMTools const CSMWorld::IdCollection& mRaces; bool mPlayable; - void performPerRecord (int stage, Messages& messages); + void performPerRecord (int stage, CSMDoc::Messages& messages); - void performFinal (Messages& messages); + void performFinal (CSMDoc::Messages& messages); public: @@ -26,7 +26,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 1816d0808..5190aacd5 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -18,7 +18,7 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( { } -void CSMTools::ReferenceableCheckStage::perform (int stage, Messages& messages) +void CSMTools::ReferenceableCheckStage::perform (int stage, CSMDoc::Messages& messages) { //Checks for books, than, when stage is above mBooksSize goes to other checks, with (stage - PrevSum) as stage. const int bookSize(mReferencables.getBooks().getSize()); @@ -232,7 +232,7 @@ int CSMTools::ReferenceableCheckStage::setup() void CSMTools::ReferenceableCheckStage::bookCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -250,7 +250,7 @@ void CSMTools::ReferenceableCheckStage::bookCheck( void CSMTools::ReferenceableCheckStage::activatorCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -270,7 +270,7 @@ void CSMTools::ReferenceableCheckStage::activatorCheck( void CSMTools::ReferenceableCheckStage::potionCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Potion >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -290,7 +290,7 @@ void CSMTools::ReferenceableCheckStage::potionCheck( void CSMTools::ReferenceableCheckStage::apparatusCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Apparatus >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -310,7 +310,7 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck( void CSMTools::ReferenceableCheckStage::armorCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Armor >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -336,7 +336,7 @@ void CSMTools::ReferenceableCheckStage::armorCheck( void CSMTools::ReferenceableCheckStage::clothingCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Clothing >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -353,7 +353,7 @@ void CSMTools::ReferenceableCheckStage::clothingCheck( void CSMTools::ReferenceableCheckStage::containerCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Container >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -381,7 +381,7 @@ void CSMTools::ReferenceableCheckStage::containerCheck( void CSMTools::ReferenceableCheckStage::creatureCheck ( int stage, const CSMWorld::RefIdDataContainer< ESM::Creature >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -448,7 +448,7 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( void CSMTools::ReferenceableCheckStage::doorCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Door >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -469,7 +469,7 @@ void CSMTools::ReferenceableCheckStage::doorCheck( void CSMTools::ReferenceableCheckStage::ingredientCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Ingredient >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -487,7 +487,7 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck( void CSMTools::ReferenceableCheckStage::creaturesLevListCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::CreatureLevList >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -505,7 +505,7 @@ void CSMTools::ReferenceableCheckStage::creaturesLevListCheck( void CSMTools::ReferenceableCheckStage::itemLevelledListCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::ItemLevList >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -522,7 +522,7 @@ void CSMTools::ReferenceableCheckStage::itemLevelledListCheck( void CSMTools::ReferenceableCheckStage::lightCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Light >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -547,7 +547,7 @@ void CSMTools::ReferenceableCheckStage::lightCheck( void CSMTools::ReferenceableCheckStage::lockpickCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Lockpick >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -567,7 +567,7 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck( void CSMTools::ReferenceableCheckStage::miscCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Miscellaneous >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -584,7 +584,7 @@ void CSMTools::ReferenceableCheckStage::miscCheck( void CSMTools::ReferenceableCheckStage::npcCheck ( int stage, const CSMWorld::RefIdDataContainer< ESM::NPC >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -701,7 +701,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( void CSMTools::ReferenceableCheckStage::weaponCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Weapon >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); @@ -778,7 +778,7 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( void CSMTools::ReferenceableCheckStage::probeCheck( int stage, const CSMWorld::RefIdDataContainer< ESM::Probe >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); @@ -796,7 +796,7 @@ void CSMTools::ReferenceableCheckStage::probeCheck( void CSMTools::ReferenceableCheckStage::repairCheck ( int stage, const CSMWorld::RefIdDataContainer< ESM::Repair >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); @@ -812,7 +812,7 @@ void CSMTools::ReferenceableCheckStage::repairCheck ( void CSMTools::ReferenceableCheckStage::staticCheck ( int stage, const CSMWorld::RefIdDataContainer< ESM::Static >& records, - Messages& messages) + CSMDoc::Messages& messages) { const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); @@ -828,7 +828,7 @@ void CSMTools::ReferenceableCheckStage::staticCheck ( //final check -void CSMTools::ReferenceableCheckStage::finalCheck (Messages& messages) +void CSMTools::ReferenceableCheckStage::finalCheck (CSMDoc::Messages& messages) { if (!mPlayerPresent) messages.push_back (std::make_pair (CSMWorld::UniversalId::Type_Referenceables, @@ -839,7 +839,7 @@ void CSMTools::ReferenceableCheckStage::finalCheck (Messages& messages) //Templates begins here template void CSMTools::ReferenceableCheckStage::inventoryItemCheck ( - const Item& someItem, Messages& messages, const std::string& someID, bool enchantable) + const Item& someItem, CSMDoc::Messages& messages, const std::string& someID, bool enchantable) { if (someItem.mName.empty()) messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name")); @@ -865,7 +865,7 @@ template void CSMTools::ReferenceableCheckStage::inventoryItemChe } template void CSMTools::ReferenceableCheckStage::inventoryItemCheck ( - const Item& someItem, Messages& messages, const std::string& someID) + const Item& someItem, CSMDoc::Messages& messages, const std::string& someID) { if (someItem.mName.empty()) messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name")); @@ -888,7 +888,7 @@ template void CSMTools::ReferenceableCheckStage::inventoryItemChe } template void CSMTools::ReferenceableCheckStage::toolCheck ( - const Tool& someTool, Messages& messages, const std::string& someID, bool canBeBroken) + const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID, bool canBeBroken) { if (someTool.mData.mQuality <= 0) messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality")); @@ -899,14 +899,14 @@ template void CSMTools::ReferenceableCheckStage::toolCheck ( } template void CSMTools::ReferenceableCheckStage::toolCheck ( - const Tool& someTool, Messages& messages, const std::string& someID) + const Tool& someTool, CSMDoc::Messages& messages, const std::string& someID) { if (someTool.mData.mQuality <= 0) messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality")); } template void CSMTools::ReferenceableCheckStage::listCheck ( - const List& someList, Messages& messages, const std::string& someID) + const List& someList, CSMDoc::Messages& messages, const std::string& someID) { for (unsigned i = 0; i < someList.mList.size(); ++i) { diff --git a/apps/opencs/model/tools/referenceablecheck.hpp b/apps/opencs/model/tools/referenceablecheck.hpp index b0129fc2a..ac7ed7082 100644 --- a/apps/opencs/model/tools/referenceablecheck.hpp +++ b/apps/opencs/model/tools/referenceablecheck.hpp @@ -17,56 +17,56 @@ namespace CSMTools const CSMWorld::IdCollection& classes, const CSMWorld::IdCollection& factions); - virtual void perform(int stage, Messages& messages); + virtual void perform(int stage, CSMDoc::Messages& messages); virtual int setup(); private: //CONCRETE CHECKS - void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, Messages& messages); - void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, Messages& messages); - void potionCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void armorCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void clothingCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void containerCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void creatureCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void doorCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void lightCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void miscCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void npcCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void weaponCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void probeCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void repairCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); - void staticCheck(int stage, const CSMWorld::RefIdDataContainer& records, Messages& messages); + void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, CSMDoc::Messages& messages); + void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, CSMDoc::Messages& messages); + void potionCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void armorCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void clothingCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void containerCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void creatureCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void doorCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void lightCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void miscCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void npcCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void weaponCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void probeCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void repairCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); + void staticCheck(int stage, const CSMWorld::RefIdDataContainer& records, CSMDoc::Messages& messages); //FINAL CHECK - void finalCheck (Messages& messages); + void finalCheck (CSMDoc::Messages& messages); //TEMPLATE CHECKS template void inventoryItemCheck(const ITEM& someItem, - Messages& messages, + CSMDoc::Messages& messages, const std::string& someID, bool enchantable); //for all enchantable items. template void inventoryItemCheck(const ITEM& someItem, - Messages& messages, + CSMDoc::Messages& messages, const std::string& someID); //for non-enchantable items. template void toolCheck(const TOOL& someTool, - Messages& messages, + CSMDoc::Messages& messages, const std::string& someID, bool canbebroken); //for tools with uses. template void toolCheck(const TOOL& someTool, - Messages& messages, + CSMDoc::Messages& messages, const std::string& someID); //for tools without uses. template void listCheck(const LIST& someList, - Messages& messages, + CSMDoc::Messages& messages, const std::string& someID); const CSMWorld::RefIdData& mReferencables; diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 07df20470..091836d0d 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -17,7 +17,7 @@ int CSMTools::RegionCheckStage::setup() return mRegions.getSize(); } -void CSMTools::RegionCheckStage::perform (int stage, Messages& messages) +void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mRegions.getRecord (stage); diff --git a/apps/opencs/model/tools/regioncheck.hpp b/apps/opencs/model/tools/regioncheck.hpp index a12903e7d..8ba32e137 100644 --- a/apps/opencs/model/tools/regioncheck.hpp +++ b/apps/opencs/model/tools/regioncheck.hpp @@ -21,7 +21,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d2c647bda..fe371a368 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -58,7 +58,7 @@ int CSMTools::ScriptCheckStage::setup() return mDocument.getData().getScripts().getSize(); } -void CSMTools::ScriptCheckStage::perform (int stage, Messages& messages) +void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) { mId = mDocument.getData().getScripts().getId (stage); diff --git a/apps/opencs/model/tools/scriptcheck.hpp b/apps/opencs/model/tools/scriptcheck.hpp index 75f11b9d4..3fe12fc9a 100644 --- a/apps/opencs/model/tools/scriptcheck.hpp +++ b/apps/opencs/model/tools/scriptcheck.hpp @@ -23,7 +23,7 @@ namespace CSMTools CSMWorld::ScriptContext mContext; std::string mId; std::string mFile; - Messages *mMessages; + CSMDoc::Messages *mMessages; virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); ///< Report error to the user. @@ -38,7 +38,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index 630516c72..e061e042c 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -16,7 +16,7 @@ int CSMTools::SkillCheckStage::setup() return mSkills.getSize(); } -void CSMTools::SkillCheckStage::perform (int stage, Messages& messages) +void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mSkills.getRecord (stage); diff --git a/apps/opencs/model/tools/skillcheck.hpp b/apps/opencs/model/tools/skillcheck.hpp index cf5d53b5c..93b06fe71 100644 --- a/apps/opencs/model/tools/skillcheck.hpp +++ b/apps/opencs/model/tools/skillcheck.hpp @@ -21,7 +21,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index 3d222e909..e122ced91 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -16,7 +16,7 @@ int CSMTools::SoundCheckStage::setup() return mSounds.getSize(); } -void CSMTools::SoundCheckStage::perform (int stage, Messages& messages) +void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mSounds.getRecord (stage); diff --git a/apps/opencs/model/tools/soundcheck.hpp b/apps/opencs/model/tools/soundcheck.hpp index a82a0eb6d..52f2d3714 100644 --- a/apps/opencs/model/tools/soundcheck.hpp +++ b/apps/opencs/model/tools/soundcheck.hpp @@ -21,7 +21,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index 3d0be46fd..0b59dc862 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -17,7 +17,7 @@ int CSMTools::SpellCheckStage::setup() return mSpells.getSize(); } -void CSMTools::SpellCheckStage::perform (int stage, Messages& messages) +void CSMTools::SpellCheckStage::perform (int stage, CSMDoc::Messages& messages) { const CSMWorld::Record& record = mSpells.getRecord (stage); diff --git a/apps/opencs/model/tools/spellcheck.hpp b/apps/opencs/model/tools/spellcheck.hpp index 182f1888b..9c3ea8885 100644 --- a/apps/opencs/model/tools/spellcheck.hpp +++ b/apps/opencs/model/tools/spellcheck.hpp @@ -21,7 +21,7 @@ namespace CSMTools virtual int setup(); ///< \return number of steps - virtual void perform (int stage, Messages& messages); + virtual void perform (int stage, CSMDoc::Messages& messages); ///< Messages resulting from this tage will be appended to \a messages. }; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f6bd8e13b..67f6822c7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -671,7 +671,7 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base return mReader->getRecordCount(); } -bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) +bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) { if (!mReader) throw std::logic_error ("can't continue loading, because no load has been started"); @@ -794,8 +794,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) } else { - messages.push_back (std::make_pair (UniversalId::Type_None, - "Trying to delete dialogue record " + id + " which does not exist")); + messages.add (UniversalId::Type_None, + "Trying to delete dialogue record " + id + " which does not exist"); } } else @@ -811,8 +811,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) { if (!mDialogue) { - messages.push_back (std::make_pair (UniversalId::Type_None, - "Found info record not following a dialogue record")); + messages.add (UniversalId::Type_None, + "Found info record not following a dialogue record"); mReader->skipRecord(); break; @@ -855,8 +855,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) if (unhandledRecord) { - messages.push_back (std::make_pair (UniversalId::Type_None, - "Unsupported record type: " + n.toString())); + messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString()); mReader->skipRecord(); } diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 37d4d4b8a..02f7bc452 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -244,7 +244,7 @@ namespace CSMWorld /// ///< \return estimated number of records - bool continueLoading (CSMDoc::Stage::Messages& messages); + bool continueLoading (CSMDoc::Messages& messages); ///< \return Finished? bool hasId (const std::string& id) const; diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index c516e2c3e..47f0276c6 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -11,7 +11,7 @@ #include "record.hpp" void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base, - std::map& cache, CSMDoc::Stage::Messages& messages) + std::map& cache, CSMDoc::Messages& messages) { Record cell = mCells.getRecord (cellIndex); @@ -36,8 +36,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell, mCells.getId (cellIndex)); - messages.push_back (std::make_pair (id, - "Attempt to delete a non-existing reference")); + messages.add (id, "Attempt to delete a non-existing reference"); continue; } diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 63d369ed9..4ecc32b2f 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -28,7 +28,7 @@ namespace CSMWorld void load (ESM::ESMReader& reader, int cellIndex, bool base, std::map& cache, - CSMDoc::Stage::Messages& messages); + CSMDoc::Messages& messages); ///< Load a sequence of references. std::string getNewId(); From a64b741af209c88d2f4269f528525690266e0a66 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Dec 2014 20:53:09 +0100 Subject: [PATCH 96/98] store hints from operations in report model --- apps/opencs/model/doc/document.cpp | 6 +++--- apps/opencs/model/doc/document.hpp | 2 +- apps/opencs/model/doc/operation.cpp | 4 ++-- apps/opencs/model/doc/operation.hpp | 2 +- apps/opencs/model/tools/tools.cpp | 8 ++++---- apps/opencs/model/tools/tools.hpp | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 4abd67a50..e688a9474 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2301,8 +2301,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); connect ( - &mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), - this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int))); + &mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), + this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged())); } @@ -2387,7 +2387,7 @@ void CSMDoc::Document::modificationStateChanged (bool clean) } void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message, - int type) + const std::string& hint, int type) { /// \todo find a better way to get these messages to the user. std::cout << message << std::endl; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index e5aa5eea5..f3aef6db6 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -149,7 +149,7 @@ namespace CSMDoc void modificationStateChanged (bool clean); void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, - int type); + const std::string& hint, int type); void operationDone (int type, bool failed); diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index a997579f8..e728050f4 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -101,7 +101,7 @@ void CSMDoc::Operation::executeStage() } catch (const std::exception& e) { - emit reportMessage (CSMWorld::UniversalId(), e.what(), mType); + emit reportMessage (CSMWorld::UniversalId(), e.what(), "", mType); abort(); } @@ -113,7 +113,7 @@ void CSMDoc::Operation::executeStage() emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); for (Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter) - emit reportMessage (iter->mId, iter->mMessage, mType); + emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType); if (mCurrentStage==mStages.end()) exit(); diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index d5a7d4e09..3c9467754 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -52,7 +52,7 @@ namespace CSMDoc void progress (int current, int max, int type); void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, - int type); + const std::string& hint, int type); void done (int type, bool failed); diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 79b0b18b0..6e157f664 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -48,8 +48,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (mVerifier, - SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), - this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int))); + SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), + this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); std::vector mandatoryIds; // I want C++11, damn it! mandatoryIds.push_back ("Day"); @@ -155,11 +155,11 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& } void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, - int type) + const std::string& hint, int type) { std::map::iterator iter = mActiveReports.find (type); if (iter!=mActiveReports.end()) - mReports[iter->second]->add (id, message); + mReports[iter->second]->add (id, message, hint); } diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 7ca30e6b9..5125a3638 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -64,7 +64,7 @@ namespace CSMTools private slots: void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, - int type); + const std::string& hint, int type); signals: From e6307a5151abff084e4bc09be6b66ccef8fef9a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 8 Dec 2014 12:29:23 +0100 Subject: [PATCH 97/98] move cursor in scripteditor to position of error --- apps/opencs/model/tools/scriptcheck.cpp | 6 +++++- apps/opencs/view/world/scriptsubview.cpp | 26 ++++++++++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 2 ++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index fe371a368..d9dea7f43 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -28,7 +28,11 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi << ", line " << loc.mLine << ", column " << loc.mColumn << " (" << loc.mLiteral << "): " << message; - mMessages->push_back (std::make_pair (id, stream.str())); + std::ostringstream hintStream; + + hintStream << "l:" << loc.mLine << " " << loc.mColumn; + + mMessages->add (id, stream.str(), hintStream.str()); } void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 22d8e7e51..9b50a61f8 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -47,6 +47,32 @@ void CSVWorld::ScriptSubView::setEditLock (bool locked) mEditor->setReadOnly (locked); } +void CSVWorld::ScriptSubView::useHint (const std::string& hint) +{ + if (hint.empty()) + return; + + if (hint[0]=='l') + { + std::istringstream stream (hint.c_str()+1); + + char ignore; + int line; + int column; + + if (stream >> ignore >> line >> column) + { + QTextCursor cursor = mEditor->textCursor(); + + cursor.movePosition (QTextCursor::Start); + if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) + cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + + mEditor->setTextCursor (cursor); + } + } +} + void CSVWorld::ScriptSubView::textChanged() { if (mEditor->isChangeLocked()) diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 77127d9be..16ffc7b80 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -34,6 +34,8 @@ namespace CSVWorld virtual void setEditLock (bool locked); + virtual void useHint (const std::string& hint); + public slots: void textChanged(); From 6c8a662042786171d3d17a6178d69a7f7e05533d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 8 Dec 2014 20:08:59 +0100 Subject: [PATCH 98/98] label local/global openmw.cfg files (Fixes #2196) --- files/openmw.cfg | 4 ++++ files/openmw.cfg.local | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/files/openmw.cfg b/files/openmw.cfg index b60c1ba72..3a9bd8762 100644 --- a/files/openmw.cfg +++ b/files/openmw.cfg @@ -1,3 +1,7 @@ +# This is the global openmw.cfg file. Do not modify! +# Modifications should be done on the user openmw.cfg file instead +# (see: https://wiki.openmw.org/index.php?title=Paths) + data="?mw?Data Files" data=${MORROWIND_DATA_FILES} data-local="?userdata?data" diff --git a/files/openmw.cfg.local b/files/openmw.cfg.local index 9d86174d9..71cd3bfbf 100644 --- a/files/openmw.cfg.local +++ b/files/openmw.cfg.local @@ -1,3 +1,7 @@ +# This is the local openmw.cfg file. Do not modify! +# Modifications should be done on the user openmw.cfg file instead +# (see: https://wiki.openmw.org/index.php?title=Paths) + data="?global?data" data="?mw?Data Files" data=./data