Projects
Multimedia
sview
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 13
View file
_service
Changed
@@ -1,7 +1,7 @@ <services> <service name="obs_scm"> <param name="filename">sview</param> - <param name="revision">b6aea11ce34d183c00177a377a7a66f13e1f535a</param> + <param name="revision">8671c35287aa8b260c788b6ccbd152ec826bcb2e</param> <param name="scm">git</param> <param name="submodules">disable</param> <param name="url">https://github.com/gkv311/sview.git</param>
View file
_service:obs_scm:sview-26.obscpio/.github/workflows/build_sview_android.yml
Changed
@@ -83,7 +83,7 @@ cp -f "./freetype.git/docs/README" "./freetype-install/" cp -f "./freetype.git/LICENSE.TXT" "./freetype-install/" - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: freetype-${{ env.SYSTEM }}-${{ env.ARCH }} path: freetype-install @@ -135,7 +135,7 @@ cp -f "./libconfig.git/LICENSE" "./libconfig-install/" cp -f "./libconfig.git/README" "./libconfig-install/" - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: libconfig-${{ env.SYSTEM }}-${{ env.ARCH }} path: libconfig-install @@ -203,7 +203,7 @@ cp -f "./openal.git/COPYING" "./openal-install/" cp -f "./openal.git/README.md" "./openal-install/" - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: openal-${{ env.SYSTEM }}-${{ env.ARCH }} path: openal-install @@ -236,22 +236,22 @@ sudo apt-get install -y \ g++ cmake ninja-build - name: Download libconfig build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: libconfig-${{ env.SYSTEM }}-${{ env.ARCH }} path: libconfig-install - name: Download FreeType build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: freetype-${{ env.SYSTEM }}-${{ env.ARCH }} path: freetype-install - name: Download OpenAL soft build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: openal-${{ env.SYSTEM }}-${{ env.ARCH }} path: openal-install - name: Download FFmpeg build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }} path: ffmpeg-install @@ -284,7 +284,7 @@ run: | cmake --build ./sview-make - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: sview-${{ env.SYSTEM }}-${{ env.ARCH }} path: sview-make/sView-Release.apk
View file
_service:obs_scm:sview-26.obscpio/.github/workflows/build_sview_android_ffmpeg.yml
Changed
@@ -82,7 +82,7 @@ cat ./mbedtls.pc popd - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: mbedtls-${{ env.SYSTEM }}-${{ env.ARCH }} path: mbedtls-install @@ -183,7 +183,7 @@ cat ./libjxl_threads.pc popd - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: libjxl-${{ env.SYSTEM }}-${{ env.ARCH }} path: libjxl-install @@ -232,7 +232,7 @@ run: | ninja -C ./dav1d-make install - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: dav1d-${{ env.SYSTEM }}-${{ env.ARCH }} path: dav1d-install @@ -273,19 +273,19 @@ fetch-depth: 1 - name: Download mbedtls build if: steps.cache.outputs.cache-hit != 'true' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: mbedtls-${{ env.SYSTEM }}-${{ env.ARCH }} path: mbedtls-install - name: Download dav1d build if: steps.cache.outputs.cache-hit != 'true' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: dav1d-${{ env.SYSTEM }}-${{ env.ARCH }} path: dav1d-install - name: Download libjxl build if: steps.cache.outputs.cache-hit != 'true' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: libjxl-${{ env.SYSTEM }}-${{ env.ARCH }} path: libjxl-install @@ -369,7 +369,7 @@ popd - name: Upload FFmpeg configure log if: steps.cache.outputs.cache-hit != 'true' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }}-config.log path: ffmpeg.git/ffbuild/config.log @@ -408,7 +408,7 @@ # copy dependencies #cp -f ./libjxl-install/lib/*.so ./ffmpeg-install/lib/ - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }} path: ffmpeg-install
View file
_service:obs_scm:sview-26.obscpio/.github/workflows/build_sview_macos.yml
Changed
@@ -73,7 +73,7 @@ tar -cf ../freetype-install.tar * popd - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: freetype-${{ env.SYSTEM }}-${{ env.ARCH }} path: freetype-install.tar @@ -138,7 +138,7 @@ tar -cf ../openal-install.tar * popd - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: openal-${{ env.SYSTEM }}-${{ env.ARCH }} path: openal-install.tar @@ -155,7 +155,7 @@ path: sview.git fetch-depth: 1 - name: Download FreeType build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: freetype-${{ env.SYSTEM }}-${{ env.ARCH }} path: freetype-install @@ -165,7 +165,7 @@ tar -xvf ./freetype-install.tar popd - name: Download OpenAL soft build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: openal-${{ env.SYSTEM }}-${{ env.ARCH }} path: openal-install @@ -175,7 +175,7 @@ tar -xvf ./openal-install.tar popd - name: Download FFmpeg build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }} path: ffmpeg-install @@ -225,7 +225,7 @@ tar -cf ../sview-${{ env.SYSTEM }}-${{ env.ARCH }}.tar * popd - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: sview-${{ env.SYSTEM }}-${{ env.ARCH }} path: sview-${{ env.SYSTEM }}-${{ env.ARCH }}.tar
View file
_service:obs_scm:sview-26.obscpio/.github/workflows/build_sview_macos_ffmpeg.yml
Changed
@@ -109,7 +109,7 @@ tar -cf ../libjxl-install.tar * popd - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: libjxl-${{ env.SYSTEM }}-${{ env.ARCH }} path: libjxl-install.tar @@ -160,7 +160,7 @@ run: | ninja -C ./dav1d-make install - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: dav1d-${{ env.SYSTEM }}-${{ env.ARCH }} path: dav1d-install @@ -201,13 +201,13 @@ fetch-depth: 1 - name: Download dav1d build if: steps.cache.outputs.cache-hit != 'true' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: dav1d-${{ env.SYSTEM }}-${{ env.ARCH }} path: dav1d-install - name: Download libjxl build if: steps.cache.outputs.cache-hit != 'true' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: libjxl-${{ env.SYSTEM }}-${{ env.ARCH }} path: libjxl-install @@ -279,7 +279,7 @@ popd - name: Upload FFmpeg configure log if: steps.cache.outputs.cache-hit != 'true' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }}-config.log path: ffmpeg.git/ffbuild/config.log @@ -329,7 +329,7 @@ tar -cf ../ffmpeg-install.tar * popd - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }} path: ffmpeg-install.tar
View file
_service:obs_scm:sview-26.obscpio/.github/workflows/build_sview_mingw.yml
Changed
@@ -19,7 +19,7 @@ FREETYPE_REF: 'VER-2-14-1' OPENAL_REF: '1.25.1' OPENVR_REF: 'v2.5.1' - CACHE_REV: 'cache3' + CACHE_REV: 'cache4' jobs: build-freetype: @@ -80,7 +80,7 @@ cp -f "./freetype.git/docs/README" "./freetype-install/" cp -f "./freetype.git/LICENSE.TXT" "./freetype-install/" - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: freetype-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: freetype-install @@ -131,9 +131,9 @@ set(ALSOFT_BACKEND_WAVE OFF CACHE BOOL "") set(ALSOFT_BACKEND_COREAUDIO OFF CACHE BOOL "") set(ALSOFT_REQUIRE_COREAUDIO OFF CACHE BOOL "") - set(ALSOFT_STATIC_LIBGCC ON CACHE BOOL "") - set(ALSOFT_STATIC_STDCXX ON CACHE BOOL "") - set(ALSOFT_STATIC_WINPTHREAD ON CACHE BOOL "") + set(ALSOFT_STATIC_LIBGCC OFF CACHE BOOL "") + set(ALSOFT_STATIC_STDCXX OFF CACHE BOOL "") + set(ALSOFT_STATIC_WINPTHREAD OFF CACHE BOOL "") ${{ env.TOOLCHAIN_TEXT }} set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_LIST_DIR}/openal-install" CACHE PATH "") run: | @@ -146,10 +146,17 @@ if: steps.cache.outputs.cache-hit != 'true' run: | cmake --install ./openal-make --prefix ./openal-install + - name: Post build + if: steps.cache.outputs.cache-hit != 'true' + run: | cp -f "./openal.git/COPYING" "./openal-install/" cp -f "./openal.git/README.md" "./openal-install/" + #cp -f /usr/${TOOLCHAIN_PREFIX}/lib/libwinpthread-1.dll ./openal-install/bin/ + #cp -f /usr/lib/gcc/${TOOLCHAIN_PREFIX}/13-posix/libstdc++-6.dll ./openal-install/bin/ + #cp -f /usr/lib/gcc/${TOOLCHAIN_PREFIX}/13-posix/libgcc_s_seh-1.dll ./openal-install/bin/ + #/usr/${TOOLCHAIN_PREFIX}/bin/strip ./openal-install/bin/libstdc++-6.dll --strip-unneeded - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: openal-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: openal-install @@ -216,9 +223,10 @@ cp -f ./openvr-install/lib/libopenvr_api64.dll.a ./openvr-install/lib/libopenvr_api.dll.a mkdir -p "./openvr-install/bin" mv -f ./openvr-install/lib/libopenvr_api64.dll ./openvr-install/bin/ + # generate header that could be used to link by MSVC python ./sview.git/3rdparty/openvr/cxx_header_generator.py -d ./openvr-install/include/ - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: openvr-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: openvr-install @@ -243,22 +251,22 @@ g++-mingw-w64-x86-64-posix gcc-mingw-w64-x86-64-posix ${TOOLCHAIN_PREFIX}-g++ --version - name: Download FreeType build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: freetype-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: freetype-install - name: Download OpenAL soft build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: openal-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: openal-install - name: Download OpenVR build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: openvr-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: openvr-install - name: Download FFmpeg build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: ffmpeg-install @@ -308,7 +316,7 @@ xvfb-run -a --server-args="-screen 0 1920x1080x24" wine \ ./sview-install/ffmpeg.exe -version - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: sview-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: ./sview-install
View file
_service:obs_scm:sview-26.obscpio/.github/workflows/build_sview_mingw_ffmpeg.yml
Changed
@@ -116,7 +116,7 @@ cat ./libjxl_threads.pc popd - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: libjxl-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: libjxl-install @@ -165,7 +165,7 @@ run: | ninja -C ./dav1d-make install - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: dav1d-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: dav1d-install @@ -206,13 +206,13 @@ fetch-depth: 1 - name: Download dav1d build if: steps.cache.outputs.cache-hit != 'true' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: dav1d-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: dav1d-install - name: Download libjxl build if: steps.cache.outputs.cache-hit != 'true' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: libjxl-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: libjxl-install @@ -283,7 +283,7 @@ popd - name: Upload FFmpeg configure log if: steps.cache.outputs.cache-hit != 'true' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }}-config.log path: ffmpeg.git/ffbuild/config.log @@ -327,7 +327,7 @@ cp -f /usr/${TOOLCHAIN_PREFIX}/lib/libwinpthread-1.dll ./ffmpeg-install/bin/ cp -f /usr/${TOOLCHAIN_PREFIX}/lib/zlib1.dll ./ffmpeg-install/bin/ - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: ffmpeg-install
View file
_service:obs_scm:sview-26.obscpio/.github/workflows/build_sview_ubuntu.yml
Changed
@@ -68,7 +68,7 @@ ./sview.git/adm/ci/screenshot.sh ./sview-install/sview-viewer-linux.png 2 \ ./sview-install/bin/sView ./sview.git/share/sView/demo/demo.jps - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: sview-${{ matrix.os }}-screenshots path: ./sview-install/*.png @@ -120,7 +120,7 @@ run: | ./sview.git/adm/ci/build_sview_android.sh #- name: Upload artifacts - # uses: actions/upload-artifact@v4 + # uses: actions/upload-artifact@v6 # with: # name: sview-apk-old # path: sview.git/build/sView-Release.apk
View file
_service:obs_scm:sview-26.obscpio/.github/workflows/build_sview_windows.yml
Changed
@@ -75,7 +75,7 @@ cp -f "./freetype.git/docs/README" "./freetype-install/" cp -f "./freetype.git/LICENSE.TXT" "./freetype-install/" - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: freetype-${{ env.SYSTEM }}-${{ env.ARCH }}-msvc path: freetype-install @@ -150,7 +150,7 @@ cp -f "./openal.git/COPYING" "./openal-install/" cp -f "./openal.git/README.md" "./openal-install/" - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: openal-${{ env.SYSTEM }}-${{ env.ARCH }}-msvc path: openal-install @@ -213,7 +213,7 @@ mkdir -p "./openvr-install/bin" mv -f ./openvr-install/lib/openvr_api64.dll ./openvr-install/bin/ - name: Upload build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: openvr-${{ env.SYSTEM }}-${{ env.ARCH }}-msvc path: openvr-install @@ -234,22 +234,22 @@ with: arch: x64 - name: Download FreeType build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: freetype-${{ env.SYSTEM }}-${{ env.ARCH }}-msvc path: freetype-install - name: Download OpenAL soft build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: openal-${{ env.SYSTEM }}-${{ env.ARCH }}-msvc path: openal-install - name: Download OpenVR build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: openvr-${{ env.SYSTEM }}-${{ env.ARCH }}-msvc path: openvr-install - name: Download FFmpeg build - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: ffmpeg-${{ env.SYSTEM }}-${{ env.ARCH }}-mingw path: ffmpeg-install @@ -291,7 +291,7 @@ # run: | # ./sview-install/ffmpeg.exe -version - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: sview-${{ env.SYSTEM }}-${{ env.ARCH }}-msvc path: sview-install
View file
_service:obs_scm:sview-26.obscpio/.gitignore
Changed
@@ -46,9 +46,11 @@ 3rdparty/include/OVR* 3rdparty/include/Extras/OVR* 3rdparty/include/rapidjson +.qtcreator/ build/ bin/ lib/ +work/ StShared/obj/ StGLWidgets/obj/ StCore/obj/
View file
_service:obs_scm:sview-26.obscpio/CHANGELOG.md
Changed
@@ -4,6 +4,21 @@ Not all changes are documented here - please check git log for complete list. +sView 26.07 (2026-07-13) +----------------------------------------------------------------------------------------------------------------------- + +- Double click is now handled to switch window fullscreen mode + (when image/video region is not dragged, otherwise image region is reset as before). +- Fixed displaying of Hiragana symbols in Japanese text. +- VR output, added 'Mirror VR to window' option. +- Linux, fixed handling of double-click. +- macOS, the threaded OpenGL mode is now disabled by default, since it leads to crashes on newest macOS versions. +- macOS, fixed hidden cursor on newest macOS. +- macOS, fixed no application focus at startup on newest macOS. +- macOS, fixed restoring of window position on second screen. +- macOS, added handling of double mouse click (in addition to double tap on a touchpad). +- macOS, respect DeepColor option (create r10g10b10a2 pixel format). + sView 26.02 (2026-02-07) -----------------------------------------------------------------------------------------------------------------------
View file
_service:obs_scm:sview-26.obscpio/CMakeLists.txt
Changed
@@ -10,8 +10,8 @@ set (APP_VERSION_MAJOR 1) set (APP_VERSION_MINOR 0) # Android APK version -set (SVIEW_APK_VERSIONCODE "52") -set (SVIEW_APK_VERSIONNAME "26.2") +set (SVIEW_APK_VERSIONCODE "54") +set (SVIEW_APK_VERSIONNAME "26.7") if (MSVC) set (BUILD_FORCE_RelWithDebInfo ON CACHE BOOL "Build release target with debug symbols")
View file
_service:obs_scm:sview-26.obscpio/StCore/StCocoaView.mm
Changed
@@ -107,98 +107,66 @@ } /** - * Left mouse button - down. + * (Any) mouse button event handler. */ - - (void ) mouseDown: (NSEvent* ) theEvent { + - (void ) mouseChange: (NSEvent* ) theEvent + button: (StVirtButton) theButton + type: (StEventType) theType { const StPointD_t aPnt = myStWin->getMousePos(); - myStEvent.Type = stEvent_MouseDown; + myStEvent.Type = theType; myStEvent.Button.Time = theEvent timestamp; - myStEvent.Button.Button = ST_MOUSE_LEFT; + myStEvent.Button.Button = theButton; myStEvent.Button.Buttons = 0; myStEvent.Button.PointX = aPnt.x(); myStEvent.Button.PointY = aPnt.y(); if(myStWin->myEventsThreaded) { myStWin->myEventsBuffer.append(myStEvent); - } else { + return; + } + + if (myStEvent.Type == stEvent_MouseDown) { myStWin->signals.onMouseDown->emit(myStEvent.Button); + } else { + myStWin->signals.onMouseUp->emit(myStEvent.Button); + // handle double mouse click (in addition to double tap on a touchpad) + myStWin->checkDoubleClick(myStEvent); } } /** + * Left mouse button - down. + */ + - (void ) mouseDown: (NSEvent* ) theEvent { + self mouseChange: theEvent button: ST_MOUSE_LEFT type: stEvent_MouseDown; + } + + /** * Left mouse button - up. */ - (void ) mouseUp: (NSEvent* ) theEvent { - const StPointD_t aPnt = myStWin->getMousePos(); - myStEvent.Type = stEvent_MouseUp; - myStEvent.Button.Time = theEvent timestamp; - myStEvent.Button.Button = ST_MOUSE_LEFT; - myStEvent.Button.Buttons = 0; - myStEvent.Button.PointX = aPnt.x(); - myStEvent.Button.PointY = aPnt.y(); - if(myStWin->myEventsThreaded) { - myStWin->myEventsBuffer.append(myStEvent); - } else { - myStWin->signals.onMouseUp->emit(myStEvent.Button); - } + self mouseChange: theEvent button: ST_MOUSE_LEFT type: stEvent_MouseUp; } /** * Right mouse button - down. */ - (void ) rightMouseDown: (NSEvent* ) theEvent { - const StPointD_t aPnt = myStWin->getMousePos(); - myStEvent.Type = stEvent_MouseDown; - myStEvent.Button.Time = theEvent timestamp; - myStEvent.Button.Button = ST_MOUSE_RIGHT; - myStEvent.Button.Buttons = 0; - myStEvent.Button.PointX = aPnt.x(); - myStEvent.Button.PointY = aPnt.y(); - if(myStWin->myEventsThreaded) { - myStWin->myEventsBuffer.append(myStEvent); - } else { - myStWin->signals.onMouseDown->emit(myStEvent.Button); - } + self mouseChange: theEvent button: ST_MOUSE_RIGHT type: stEvent_MouseDown; } /** * Right mouse button - up. */ - (void ) rightMouseUp: (NSEvent* ) theEvent { - const StPointD_t aPnt = myStWin->getMousePos(); - myStEvent.Type = stEvent_MouseUp; - myStEvent.Button.Time = theEvent timestamp; - myStEvent.Button.Button = ST_MOUSE_RIGHT; - myStEvent.Button.Buttons = 0; - myStEvent.Button.PointX = aPnt.x(); - myStEvent.Button.PointY = aPnt.y(); - if(myStWin->myEventsThreaded) { - myStWin->myEventsBuffer.append(myStEvent); - } else { - myStWin->signals.onMouseUp->emit(myStEvent.Button); - } + self mouseChange: theEvent button: ST_MOUSE_RIGHT type: stEvent_MouseUp; } /** * Another (nor left nor right) mouse button - down. */ - (void ) otherMouseDown: (NSEvent* ) theEvent { - StVirtButton aBtnId = ST_NOMOUSE; if(theEvent buttonNumber == 2) { - aBtnId = ST_MOUSE_MIDDLE; - } - if(aBtnId != ST_NOMOUSE) { - const StPointD_t aPnt = myStWin->getMousePos(); - myStEvent.Type = stEvent_MouseDown; - myStEvent.Button.Time = theEvent timestamp; - myStEvent.Button.Button = aBtnId; - myStEvent.Button.Buttons = 0; - myStEvent.Button.PointX = aPnt.x(); - myStEvent.Button.PointY = aPnt.y(); - if(myStWin->myEventsThreaded) { - myStWin->myEventsBuffer.append(myStEvent); - } else { - myStWin->signals.onMouseDown->emit(myStEvent.Button); - } + self mouseChange: theEvent button: ST_MOUSE_MIDDLE type: stEvent_MouseDown; } } @@ -206,23 +174,8 @@ * Another (nor left nor right) mouse button - up. */ - (void ) otherMouseUp: (NSEvent* ) theEvent { - StVirtButton aBtnId = ST_NOMOUSE; if(theEvent buttonNumber == 2) { - aBtnId = ST_MOUSE_MIDDLE; - } - if(aBtnId != ST_NOMOUSE) { - const StPointD_t aPnt = myStWin->getMousePos(); - myStEvent.Type = stEvent_MouseUp; - myStEvent.Button.Time = theEvent timestamp; - myStEvent.Button.Button = aBtnId; - myStEvent.Button.Buttons = 0; - myStEvent.Button.PointX = aPnt.x(); - myStEvent.Button.PointY = aPnt.y(); - if(myStWin->myEventsThreaded) { - myStWin->myEventsBuffer.append(myStEvent); - } else { - myStWin->signals.onMouseUp->emit(myStEvent.Button); - } + self mouseChange: theEvent button: ST_MOUSE_MIDDLE type: stEvent_MouseUp; } } @@ -601,8 +554,13 @@ } - (void ) resetCursorRects { + super resetCursorRects; if(myToHideCursor) { self addCursorRect: self visibleRect cursor: myBlankCursor; + } else { + // required on newest macOS with all events hanlded in GUI thread + // (probably could be fixed somewhere else...) + self addCursorRect: self visibleRect cursor: NSCursor arrowCursor; } }
View file
_service:obs_scm:sview-26.obscpio/StCore/StCocoaWin.h
Changed
@@ -26,11 +26,13 @@ * Main constructor. * @param theStWin (StWindowImpl* ) - StWindowImpl instance to send events; * @param theRect (StRectI_t ) - window content placement, in normal units; + * @param theScreen (NSScreen* ) - screen to display window on; * @param theWinStyle (NSUInteger ) - window style; * @return initialized instance on success or NULL otherwise. */ - (id ) initWithStWin: (StWindowImpl* ) theStWin rect: (StRectI_t ) theRect + screen: (NSScreen* ) theScreen styleMask: (NSUInteger ) theWinStyle; /**
View file
_service:obs_scm:sview-26.obscpio/StCore/StCocoaWin.mm
Changed
@@ -14,12 +14,21 @@ - (id ) initWithStWin: (StWindowImpl* ) theStWin rect: (StRectI_t ) theRect + screen: (NSScreen* ) theScreen styleMask: (NSUInteger ) theWinStyle { + NSRect aRectNs = theStWin->myCocoaCoords.normalToCocoa(theRect); + if (theScreen != nullptr) { + NSRect aScreenRect = theScreen frame; + aRectNs.origin.x -= aScreenRect.origin.x; + aRectNs.origin.y -= aScreenRect.origin.y; + } + self = super initWithContentRect: aRectNs styleMask: theWinStyle backing: NSBackingStoreBuffered - defer: NO; + defer: NO + screen: theScreen; if(self == NULL) { return NULL; }
View file
_service:obs_scm:sview-26.obscpio/StCore/StSearchMonitors.ObjC.mm
Changed
@@ -8,24 +8,19 @@ #include <StCore/StSearchMonitors.h> #include <StStrings/StLogger.h> +#include <StCocoa/StCocoaCoords.h> #include <StCocoa/StCocoaLocalPool.h> #import <Cocoa/Cocoa.h> #import <IOKit/graphics/IOGraphicsLib.h> -#if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) -@interface NSScreen (LionAPI) - - (CGFloat )backingScaleFactor; -@end -#endif - namespace { /** * Retrieve number from NSNumber. */ - inline uint32_t getNumber(NSNumber* theNum) { - if(theNum == NULL + static uint32_t getNumber(NSNumber* theNum) { + if (theNum == nullptr || !theNum isKindOfClass: NSNumber class) { return 0; } @@ -38,22 +33,22 @@ static NSDictionary* findDispInfo(CGDirectDisplayID theDispId) { io_iterator_t anIter; CFMutableDictionaryRef aMatching = IOServiceMatching("IODisplayConnect"); - if(IOServiceGetMatchingServices(kIOMasterPortDefault, aMatching, &anIter) != KERN_SUCCESS) { - return NULL; + if (IOServiceGetMatchingServices(kIOMasterPortDefault, aMatching, &anIter) != KERN_SUCCESS) { + return nullptr; } const uint32_t aVendId = CGDisplayVendorNumber(theDispId); const uint32_t aProdId = CGDisplayModelNumber (theDispId); const uint32_t aSerial = CGDisplaySerialNumber(theDispId); - for(io_service_t aServ = IOIteratorNext(anIter); aServ != 0; aServ = IOIteratorNext(anIter)) { + for (io_service_t aServ = IOIteratorNext(anIter); aServ != 0; aServ = IOIteratorNext(anIter)) { NSDictionary* aDevInfo = (NSDictionary* )IODisplayCreateInfoDictionary(aServ, kIODisplayOnlyPreferredName); NSNumber* aVendIdRef = aDevInfo objectForKey: NSString stringWithUTF8String: kDisplayVendorID; NSNumber* aProdIdRef = aDevInfo objectForKey: NSString stringWithUTF8String: kDisplayProductID; NSNumber* aSerialRef = aDevInfo objectForKey: NSString stringWithUTF8String: kDisplaySerialNumber; - if(getNumber(aVendIdRef) == aVendId - && getNumber(aProdIdRef) == aProdId - && getNumber(aSerialRef) == aSerial) { + if (getNumber(aVendIdRef) == aVendId + && getNumber(aProdIdRef) == aProdId + && getNumber(aSerialRef) == aSerial) { IOObjectRelease(anIter); return aDevInfo; } @@ -61,70 +56,68 @@ aDevInfo release; } - ST_ERROR_LOG("StSearchMonitors, no match between NS and CF display"); + // unfortunately, on Apple ARM processors this API doesn't work anymore, + // hense report a warning, and not an error message + ST_DEBUG_LOG("StSearchMonitors, no match between NS and CF display"); IOObjectRelease(anIter); - return NULL; + return nullptr; } } void StSearchMonitors::findMonitorsCocoa() { - if(NSApp == NULL) { + if (NSApp == nullptr) { return; } + StCocoaLocalPool aLocalPool; NSArray* aScreens = NSScreen screens; - if(aScreens == NULL) { + if (aScreens == nullptr || aScreens count == 0) { return; } - for(NSUInteger aScrId = 0; aScrId < aScreens count; ++aScrId) { + StCocoaCoords aConverter; + for (NSUInteger aScrId = 0; aScrId < aScreens count; ++aScrId) { StMonitor aStMon; aStMon.setId(aScrId); NSScreen* aScreen = (NSScreen* )aScreens objectAtIndex: aScrId; NSDictionary* aDict = aScreen deviceDescription; NSNumber* aNumber = aDict objectForKey: @"NSScreenNumber"; - if(aNumber == NULL + if (aNumber == nullptr || aNumber isKindOfClass: NSNumber class == NO) { ST_DEBUG_LOG("StSearchMonitors, invalid Cocoa screen #" + aScrId); continue; } - CGDirectDisplayID aDispId = aNumber unsignedIntValue; - CGRect aRectCg = CGDisplayBounds(aDispId); - - GLfloat aScale = 1.0f; - if(aScreen respondsToSelector: @selector(backingScaleFactor)) { - aScale = aScreen backingScaleFactor; + if (aScreen respondsToSelector: @selector(backingScaleFactor)) { + aStMon.setScale(aScreen backingScaleFactor); } - #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 - else { - aScale = aScreen userSpaceScaleFactor; - } - #endif - aStMon.setScale(aScale); - aStMon.setVRect(StRectI_t(aRectCg.origin.y, aRectCg.origin.y + aRectCg.size.height, - aRectCg.origin.x, aRectCg.origin.x + aRectCg.size.width)); + const NSRect aRectCg = aScreen frame; + const StRectI_t aRectI = aConverter.cocoaToNormal(aRectCg); + aStMon.setVRect(aRectI); + + if (@available(macOS 10.15, *)) { + aStMon.setName(StString(aScreen localizedName UTF8String)); + } + aStMon.setWideGamut(aScreen canRepresentDisplayGamut: NSDisplayGamutP3); - //boolean_t isActive = CGDisplayIsActive(aDispId); - //boolean_t isStereoOn = CGDisplayIsStereo(aDispId); - //double CGDisplayModeGetRefreshRate(CGDisplayModeRef mode); + const CGDirectDisplayID aDispId = aNumber unsignedIntValue; // retrieve low-level information about device NSDictionary* aDevInfo = (NSDictionary* )findDispInfo(aDispId); //NSDictionary* aDevInfo = (NSDictionary* )IODisplayCreateInfoDictionary(CGDisplayIOServicePort(aDispId), kIODisplayOnlyPreferredName); // retrieve display name - NSDictionary* aLocalizedNames = NULL; - if(aDevInfo != NULL) { + NSDictionary* aLocalizedNames = nullptr; + if (aDevInfo != nullptr) { aLocalizedNames = aDevInfo objectForKey: NSString stringWithUTF8String: kDisplayProductName; } - if(aLocalizedNames != NULL + if (aLocalizedNames != nullptr && aLocalizedNames isKindOfClass: NSDictionary class && aLocalizedNames count > 0) { NSString* aScreenName = aLocalizedNames objectForKey: aLocalizedNames allKeys objectAtIndex: 0; - if(aScreenName != NULL + if (aScreenName != nullptr && aScreenName isKindOfClass: NSString class) { aStMon.setName(StString(aScreenName UTF8String)); } @@ -132,11 +125,11 @@ // retrieve EDID NSData* anEDID = aDevInfo objectForKey: NSString stringWithUTF8String: kIODisplayEDIDKey; - if(anEDID != NULL + if (anEDID != nullptr && anEDID isKindOfClass: NSData class && anEDID length != 0) { aStMon.changeEdid().init((unsigned char* )anEDID bytes, anEDID length); - if(aStMon.getEdid().isValid()) { + if (aStMon.getEdid().isValid()) { aStMon.setPnPId(aStMon.getEdid().getPnPId()); } }
View file
_service:obs_scm:sview-26.obscpio/StCore/StWindowImpl.cpp
Changed
@@ -1452,6 +1452,38 @@ } } +void StWindowImpl::checkDoubleClick(const StEvent& theEvent) { + if (theEvent.Type != stEvent_MouseDown + && theEvent.Type == stEvent_MouseCancel) { + return; + } + + if (theEvent.Button.Button != ST_MOUSE_LEFT + || theEvent.Type == stEvent_MouseCancel) { + myDoubleClickTimer.stop(); + return; + } + + // check double click + const StRectI_t& aWinRect = attribs.IsFullScreen ? myRectFull : myRectNorm; + const StPointD_t aNewPnt(theEvent.Button.PointX, theEvent.Button.PointY); + const StPointD_t aDeltaPx = (myDoubleClickPnt - aNewPnt) * StPointD_t(aWinRect.width(), aWinRect.height()); + if (myDoubleClickTimer.isOn() + && myDoubleClickTimer.getElapsedTime() < 0.4 + && aDeltaPx.cwiseAbs().maxComp() < 3) { + myStEvent2.Type = stEvent_Gesture1DoubleTap; + myStEvent2.Gesture.clearGesture(); + myStEvent2.Gesture.Time = theEvent.Button.Time; + myStEvent2.Gesture.Point1X = (float )theEvent.Button.PointX; + myStEvent2.Gesture.Point1Y = (float )theEvent.Button.PointY; + myDoubleClickTimer.stop(); + signals.onGesture->emit(myStEvent2.Gesture); + } else { + myDoubleClickTimer.restart(); + } + myDoubleClickPnt = aNewPnt; +} + void StWindowImpl::swapEventsBuffers() { myEventsBuffer.swapBuffers(); for(size_t anEventIter = 0; anEventIter < myEventsBuffer.getSize(); ++anEventIter) { @@ -1491,30 +1523,7 @@ case stEvent_MouseCancel: case stEvent_MouseUp: { signals.onMouseUp->emit(anEvent.Button); - if(anEvent.Button.Button != ST_MOUSE_LEFT - || anEvent.Type == stEvent_MouseCancel) { - myDoubleClickTimer.stop(); - break; - } - - // check double click - const StRectI_t& aWinRect = attribs.IsFullScreen ? myRectFull : myRectNorm; - const StPointD_t aNewPnt(anEvent.Button.PointX, anEvent.Button.PointY); - const StPointD_t aDeltaPx = (myDoubleClickPnt - aNewPnt) * StPointD_t(aWinRect.width(), aWinRect.height()); - if(myDoubleClickTimer.isOn() - && myDoubleClickTimer.getElapsedTime() < 0.4 - && aDeltaPx.cwiseAbs().maxComp() < 3) { - myStEvent2.Type = stEvent_Gesture1DoubleTap; - myStEvent2.Gesture.clearGesture(); - myStEvent2.Gesture.Time = anEvent.Button.Time; - myStEvent2.Gesture.Point1X = (float )anEvent.Button.PointX; - myStEvent2.Gesture.Point1Y = (float )anEvent.Button.PointY; - myDoubleClickTimer.stop(); - signals.onGesture->emit(myStEvent2.Gesture); - } else { - myDoubleClickTimer.restart(); - } - myDoubleClickPnt = aNewPnt; + checkDoubleClick(anEvent); break; } case stEvent_TouchDown:
View file
_service:obs_scm:sview-26.obscpio/StCore/StWindowImpl.h
Changed
@@ -130,6 +130,11 @@ ST_LOCAL void swapEventsBuffers(); /** + * Check stEvent_MouseUp event and generate stEvent_Gesture1DoubleTap event. + */ + ST_LOCAL void checkDoubleClick(const StEvent& theEvent); + + /** * @return uptime in seconds for event */ ST_LOCAL double getEventTime() const;
View file
_service:obs_scm:sview-26.obscpio/StCore/StWindowImplLin.cpp
Changed
@@ -1021,6 +1021,11 @@ myStEvent.Type = stEvent_MouseUp; signals.onMouseUp->emit(myStEvent.Button); } + + // check double click + if (myStEvent.Type == stEvent_MouseUp) { + checkDoubleClick(myStEvent); + } break; } //case ResizeRequest:
View file
_service:obs_scm:sview-26.obscpio/StCore/StWindowImplMac.mm
Changed
@@ -187,12 +187,21 @@ NSOpenGLContext* theGLContextSlave) { StCocoaLocalPool aLocalPool; + const int aMainWinModId = myMonitorsmyRectNorm.center().getId(); + + NSScreen* aScreen = nullptr; + NSArray* aScreens = NSScreen screens; + if (aScreens != nullptr && aMainWinModId < aScreens count) { + aScreen = (NSScreen* )aScreens objectAtIndex: aMainWinModId; + } + // create the Master window NSUInteger aWinStyle = attribs.IsNoDecor ? NSBorderlessWindowMask : NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask; myMaster.hWindow = StCocoaWin alloc initWithStWin: this rect: myRectNorm + screen: aScreen styleMask: aWinStyle; if(myMaster.hWindow == NULL) { stError("Cocoa, Master Window Creation Error"); @@ -202,6 +211,13 @@ StCocoaString aTitle(myWindowTitle); myMaster.hWindow setTitle: aTitle.toStringNs(); + // adjust resize increments to keep size aligned... + // doesn't look practically useful (the window movement is more important), but anyhow + if (attribs.ToAlignEven) { + NSSize anIncr = { 2.0f, 2.0f }; + myMaster.hWindow setResizeIncrements: anIncr; + } + // create the view in Master window myMaster.hViewGl = StCocoaView alloc initWithStWin: this nsWin: myMaster.hWindow; @@ -220,8 +236,14 @@ // create the Slave window StRectI_t aRectSlave(getSlaveTop(), getSlaveTop() + getSlaveHeight(), getSlaveLeft(), getSlaveLeft() + getSlaveWidth()); + const int aSlaveWinModId = myMonitorsaRectSlave.center().getId(); + if (aScreens != nullptr && aSlaveWinModId < aScreens count) { + aScreen = (NSScreen* )aScreens objectAtIndex: aSlaveWinModId; + } + mySlave.hWindow = StCocoaWin alloc initWithStWin: this rect: aRectSlave + screen: aScreen styleMask: NSBorderlessWindowMask; if(mySlave.hWindow == NULL) { myMaster.close(); @@ -255,6 +277,8 @@ } myMaster.hWindow makeKeyAndOrderFront: NSApp; + // required for macOS Catalina+ to make application focused + NSApp activateIgnoringOtherApps: YES; } bool StWindowImpl::create() { @@ -263,7 +287,7 @@ myInitState = STWIN_INITNOTSTART; updateChildRect(); - if(NSApp == NULL) { + if (NSApp == nullptr) { stError("Cocoa, main application doesn't exists"); myInitState = STWIN_ERROR_COCOA_NO_APP; return false; @@ -271,49 +295,67 @@ StCocoaLocalPool aLocalPool; - const bool isNoAccel = false; -ST_DISABLE_DEPRECATION_WARNINGS - const NSOpenGLPixelFormatAttribute aDummyAttrib = NSOpenGLPFACompliant; -ST_ENABLE_DEPRECATION_WARNINGS - NSOpenGLPixelFormatAttribute anAttribs = { - attribs.IsGlStereo ? NSOpenGLPFAStereo : aDummyAttrib, - //NSOpenGLPFAColorSize, 32, - //NSOpenGLPFADepthSize, 0, - //NSOpenGLPFAStencilSize, 0, - NSOpenGLPFADoubleBuffer, - isNoAccel ? NSOpenGLPFARendererID : NSOpenGLPFAAccelerated, - isNoAccel ? kCGLRendererGenericFloatID : 0, - 0 + const auto fillAttribs = this(std::vector<NSOpenGLPixelFormatAttribute>& theAttribs, + const bool theIsStereo) { + const bool isNoAccel = false; + theAttribs.clear(); + theAttribs.push_back(NSOpenGLPFADoubleBuffer); + if (isNoAccel) { + theAttribs.push_back(NSOpenGLPFARendererID); + theAttribs.push_back(kCGLRendererGenericFloatID); + } else { + theAttribs.push_back(NSOpenGLPFAAccelerated); + } + if (theIsStereo) { + theAttribs.push_back(NSOpenGLPFAStereo); + } + if (attribs.GlColorSize == 30) { + theAttribs.push_back(NSOpenGLPFAColorSize); + theAttribs.push_back(30); + theAttribs.push_back(NSOpenGLPFAAlphaSize); + theAttribs.push_back(2); + } + if (attribs.GlDepthSize != 0) { + theAttribs.push_back(NSOpenGLPFADepthSize); + theAttribs.push_back(attribs.GlDepthSize); + } + if (attribs.GlStencilSize != 0) { + theAttribs.push_back(NSOpenGLPFAStencilSize); + theAttribs.push_back(attribs.GlStencilSize); + } + theAttribs.push_back(0); }; + std::vector<NSOpenGLPixelFormatAttribute> anAttribs; + fillAttribs(anAttribs, attribs.IsGlStereo); + // create the Master GL context ///NSOpenGLPixelFormat* aGlFormatMaster = NSOpenGLView class defaultPixelFormat retain; - NSOpenGLPixelFormat* aGLFormat = NULL; - NSOpenGLContext* aGLContextMaster = NULL; - NSOpenGLContext* aGLContextSlave = NULL; + NSOpenGLPixelFormat* aGLFormat = nullptr; + NSOpenGLContext* aGLContextMaster = nullptr; + NSOpenGLContext* aGLContextSlave = nullptr; - aGLFormat = NSOpenGLPixelFormat alloc initWithAttributes: anAttribs autorelease; + aGLFormat = NSOpenGLPixelFormat alloc initWithAttributes: anAttribs.data() autorelease; aGLContextMaster = NSOpenGLContext alloc initWithFormat: aGLFormat - shareContext: NULL autorelease; - if(aGLContextMaster == NULL - && attribs.IsGlStereo) { + shareContext: nullptr autorelease; + if (aGLContextMaster == nullptr && attribs.IsGlStereo) { ST_ERROR_LOG("Cocoa, fail to create Quad Buffered OpenGL context"); - anAttribs0 = aDummyAttrib; - aGLFormat = NSOpenGLPixelFormat alloc initWithAttributes: anAttribs autorelease; + fillAttribs(anAttribs, false); + aGLFormat = NSOpenGLPixelFormat alloc initWithAttributes: anAttribs.data() autorelease; aGLContextMaster = NSOpenGLContext alloc initWithFormat: aGLFormat - shareContext: NULL autorelease; + shareContext: nullptr autorelease; } - if(aGLContextMaster == NULL) { + if (aGLContextMaster == nullptr) { stError("Cocoa, fail to create Double Buffered OpenGL context"); myInitState = STWIN_ERROR_COCOA_NO_GL; return false; } // create the Slave GL context - if(attribs.Slave != StWinSlave_slaveOff) { + if (attribs.Slave != StWinSlave_slaveOff) { aGLContextSlave = NSOpenGLContext alloc initWithFormat: aGLFormat shareContext: aGLContextMaster autorelease; - if(aGLContextSlave == NULL) { + if (aGLContextSlave == NULL) { stError("Cocoa, fail to create Slave OpenGL context"); myInitState = STWIN_ERROR_COCOA_NO_GL; return false; @@ -324,27 +366,27 @@ StWinInitInfo* aWinInit = StWinInitInfo alloc init: this master: aGLContextMaster slave: aGLContextSlave; - if(aWinInit == NULL) { + if (aWinInit == nullptr) { myInitState = STWIN_ERROR_COCOA_CREATEWIN; return false; } - if(NSThread isMainThread) { - aWinInit doCreateWindows: NULL; + if (NSThread isMainThread) { + aWinInit doCreateWindows: nullptr; } else { aWinInit performSelectorOnMainThread: @selector(doCreateWindows:) - withObject: NULL + withObject: nullptr waitUntilDone: YES; } aWinInit release; - if(myInitState != STWIN_INITNOTSTART) { + if (myInitState != STWIN_INITNOTSTART) { return false; } myMaster.glMakeCurrent(); myGlContext = new StGLContext(myResMgr); - if(!myGlContext->stglInit()) { + if (!myGlContext->stglInit()) { stError("Critical error - broken GL context!\nInvalid OpenGL driver?"); myInitState = STWIN_ERROR_COCOA_NO_GL; return false;
View file
_service:obs_scm:sview-26.obscpio/StGLWidgets/StGLImageRegion.cpp
Changed
@@ -1566,7 +1566,11 @@ return false; } case stEvent_Gesture1DoubleTap: { - doParamsReset(0); + bool isChanged = resetParams(); + if (!params.IsFullscreen.isNull() && !isChanged) { + /// TODO add option + params.IsFullscreen->reverse(); + } //aParams->ScaleFactor = 1.0f; return true; } @@ -1693,14 +1697,18 @@ params.stereoFile->setXRotate(anXRotate); } -void StGLImageRegion::doParamsReset(const size_t ) { - params.SeparationDX->reset(); - params.SeparationDY->reset(); - params.SeparationRot->reset(); +bool StGLImageRegion::resetParams() { + bool hasChanges = false; + hasChanges = params.SeparationDX->reset() || hasChanges; + hasChanges = params.SeparationDY->reset() || hasChanges; + hasChanges = params.SeparationRot->reset() || hasChanges; if(!params.stereoFile.isNull()) { - params.stereoFile->reset(); + hasChanges = params.stereoFile->reset() || hasChanges; + } + if (hasChanges) { + onParamsChanged(); } - onParamsChanged(); + return hasChanges; } void StGLImageRegion::onParamsChanged() {
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/StImageLoader.h
Changed
@@ -136,6 +136,11 @@ ST_LOCAL void setCompressMemory(const bool theToCompress); /** + * Get theater mode. + */ + ST_LOCAL bool isTheaterMode() const { return myIsTheaterMode; } + + /** * Set theater mode. */ ST_LOCAL void setTheaterMode(bool theIsTheater) {
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/StImageViewer.cpp
Changed
@@ -372,6 +372,11 @@ addAction(Action_PanoramaOnOff, anAction, ST_VK_P); } { + StHandle<StActionIntSlot> anAction = new StActionIntSlot(stCString("DoTheaterOnOff"), 0); + anAction->setSlot(stSlot(this, &StImageViewer::doTheaterOnOff)); + addAction(Action_TheaterOnOff, anAction, ST_VK_P | ST_VF_CONTROL, ST_VK_T); + } + { StHandle<StActionIntSlot> anAction = new StActionIntSlot(stCString("DoOutStereoNormal"), StGLImageRegion::MODE_STEREO); anAction->setSlot(stSlot(this, &StImageViewer::doSetStereoOutput)); addAction(Action_OutStereoNormal, anAction); @@ -1321,6 +1326,17 @@ myGUI->myImage->params.DisplayMode->setValue((int32_t )theMode); } +void StImageViewer::doTheaterOnOff(const size_t ) { + if(myLoader.isNull()) { + return; + } + + myLoader->setTheaterMode(!myLoader->isTheaterMode()); + if (!myPlayList->isEmpty()) { + myLoader->doLoadNext(); + } +} + void StImageViewer::doPanoramaOnOff(const size_t ) { if(myLoader.isNull()) { return;
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/StImageViewer.h
Changed
@@ -196,6 +196,7 @@ ST_LOCAL void doSwitchViewMode(const int32_t theMode); ST_LOCAL void doSetStereoOutput(const size_t theMode); ST_LOCAL void doPanoramaOnOff(const size_t ); + ST_LOCAL void doTheaterOnOff(const size_t ); ST_LOCAL void doChangeSwapJPS(const bool ); ST_LOCAL void doChangeStickPano360(const bool ); ST_LOCAL void doChangeFlipCubeZ(const bool ); @@ -232,7 +233,9 @@ Action_StereoParamsBegin, Action_StereoParamsEnd = Action_StereoParamsBegin + StGLImageRegion::ActionsNb - 1, Action_PanoramaOnOff, + Action_TheaterOnOff, Action_ShowGUI, + // aliases Action_OutStereoNormal, Action_OutStereoLeftView, Action_OutStereoRightView,
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/StImageViewerGUI.cpp
Changed
@@ -1307,6 +1307,7 @@ myImage->changeIconNext()->setDrawShadow(true); myImage->signals.onOpenItem = stSlot(myPlugin, &StImageViewer::doFileNext); myImage->setPlayList(thePlayList); + myImage->params.IsFullscreen = myPlugin->params.IsFullscreen; myImage->params.DisplayMode->setName(tr(MENU_VIEW_DISPLAY_MODE)); myImage->params.DisplayMode->changeValues()StGLImageRegion::MODE_STEREO = tr(MENU_VIEW_DISPLAY_MODE_STEREO); myImage->params.DisplayMode->changeValues()StGLImageRegion::MODE_ONLY_LEFT = tr(MENU_VIEW_DISPLAY_MODE_LEFT);
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/StImageViewerStrings.cpp
Changed
@@ -475,6 +475,9 @@ addAction(theStrings, StImageViewer::Action_PanoramaOnOff, "DoPanoramaOnOff", "Enable/disable panorama mode"); + addAction(theStrings, StImageViewer::Action_TheaterOnOff, + "DoTheaterOnOff", + "Enable/disable theater mode"); addAction(theStrings, StImageViewer::Action_ShowGUI, "DoShowGUI", "Show/hide GUI");
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/chinese/StImageViewer.lng
Changed
@@ -188,4 +188,5 @@ ?6042=X Rotation - up ?6043=X Rotation - down ?6044=Enable/disable panorama mode -?6045=Show/hide GUI +?6045=Enable/disable theater mode +?6046=Show/hide GUI
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/chineset/StImageViewer.lng
Changed
@@ -188,4 +188,5 @@ 6042=X軸旋轉 - 上 6043=X軸旋轉 - 下 6044=開啟 / 關閉 環景模式 -6045=開啟 / 關閉 圖形化使用者介面 +6045=開啟 / 關閉 劇院模式 +6046=開啟 / 關閉 圖形化使用者介面
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/czech/StImageViewer.lng
Changed
@@ -189,4 +189,5 @@ ?6042=X Rotation - up ?6043=X Rotation - down ?6044=Enable/disable panorama mode -?6045=Show/hide GUI +?6045=Enable/disable theater mode +?6046=Show/hide GUI
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/english/StImageViewer.lng
Changed
@@ -188,4 +188,5 @@ 6042=X Rotation - up 6043=X Rotation - down 6044=Enable/disable panorama mode -6045=Show/hide GUI +6045=Enable/disable theater mode +6046=Show/hide GUI
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/french/StImageViewer.lng
Changed
@@ -188,4 +188,5 @@ ?6042=X Rotation - up ?6043=X Rotation - down 6044=Activer / désactiver le mode panorama -6045=Masquer l'interface +6045=Activer / désactiver le mode théâtre +6046=Masquer l'interface
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/german/StImageViewer.lng
Changed
@@ -188,4 +188,5 @@ 6042=X-Drehung - nach oben 6043=X-Drehung - nach unten 6044=Aktivieren / Deaktivieren der Panorama-Modus -6045=GUI ausblenden +6045=Aktivieren / Deaktivieren der Theater-Modus +6046=GUI ausblenden
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/korean/StImageViewer.lng
Changed
@@ -189,4 +189,5 @@ ?6042=X Rotation - up ?6043=X Rotation - down ?6044=Enable/disable panorama mode -?6045=Show/hide GUI +?6045=Enable/disable theater mode +?6046=Show/hide GUI
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/russian/StImageViewer.lng
Changed
@@ -188,4 +188,5 @@ 6042=X наклон - наверх 6043=X наклон - вниз 6044=Включить/выключить панорамный режим -6045=Скрыть интерфейс +6045=Включить/выключить театральный режим +6046=Скрыть интерфейс
View file
_service:obs_scm:sview-26.obscpio/StImageViewer/lang/spanish/StImageViewer.lng
Changed
@@ -187,4 +187,5 @@ 6042=Rotación X: arriba 6043=Rotación X: abajo 6044=Activar/Desactivar modo panorámico -6045=Mostrar/ocultar GUI +6045=Activar/Desactivar modo teatro +6046=Mostrar/ocultar GUI
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/StMoviePlayer.cpp
Changed
@@ -684,6 +684,11 @@ addAction(Action_PanoramaOnOff, anAction, ST_VK_P); } { + StHandle<StActionIntSlot> anAction = new StActionIntSlot(stCString("DoTheaterOnOff"), 0); + anAction->setSlot(stSlot(this, &StMoviePlayer::doTheaterOnOff)); + addAction(Action_TheaterOnOff, anAction, ST_VK_P | ST_VF_CONTROL); + } + { StHandle<StActionIntSlot> anAction = new StActionIntSlot(stCString("DoOutStereoNormal"), StGLImageRegion::MODE_STEREO); anAction->setSlot(stSlot(this, &StMoviePlayer::doSetStereoOutput)); addAction(Action_OutStereoNormal, anAction); @@ -2099,6 +2104,14 @@ myVideo->setTheaterMode(theMode == StViewSurface_Theater); } +void StMoviePlayer::doTheaterOnOff(const size_t ) { + if(myVideo.isNull()) { + return; + } + + myVideo->setTheaterMode(!myVideo->isTheaterMode()); +} + void StMoviePlayer::doPanoramaOnOff(const size_t ) { if(myVideo.isNull()) { return;
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/StMoviePlayer.h
Changed
@@ -325,6 +325,7 @@ ST_LOCAL void doSetStereoOutput(const size_t theMode); ST_LOCAL void doSwitchViewMode(const int32_t theMode); ST_LOCAL void doPanoramaOnOff(const size_t ); + ST_LOCAL void doTheaterOnOff(const size_t ); ST_LOCAL void doChangeStickPano360(const bool ); ST_LOCAL void doChangeSwapJPS(const bool ); ST_LOCAL void doSwitchAudioStream(const int32_t theStreamId); @@ -381,7 +382,9 @@ Action_StereoParamsBegin, Action_StereoParamsEnd = Action_StereoParamsBegin + StGLImageRegion::ActionsNb - 1, Action_PanoramaOnOff, + Action_TheaterOnOff, Action_ShowGUI, + // aliases Action_OutStereoNormal, Action_OutStereoLeftView, Action_OutStereoRightView,
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/StMoviePlayerGUI.cpp
Changed
@@ -1694,6 +1694,7 @@ myImage->signals.onOpenItem = stSlot(myPlugin, &StMoviePlayer::doFileNext); myImage->setPlayList(thePlayList); //myImage->setDragDelayMs(500.0); + myImage->params.IsFullscreen = myPlugin->params.IsFullscreen; myImage->params.DisplayMode->setName(tr(MENU_VIEW_DISPLAY_MODE)); myImage->params.DisplayMode->changeValues()StGLImageRegion::MODE_STEREO = tr(MENU_VIEW_DISPLAY_MODE_STEREO); myImage->params.DisplayMode->changeValues()StGLImageRegion::MODE_ONLY_LEFT = tr(MENU_VIEW_DISPLAY_MODE_LEFT);
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/StMoviePlayerStrings.cpp
Changed
@@ -669,6 +669,9 @@ addAction(theStrings, StMoviePlayer::Action_PanoramaOnOff, "DoPanoramaOnOff", "Enable/disable panorama mode"); + addAction(theStrings, StMoviePlayer::Action_TheaterOnOff, + "DoTheaterOnOff", + "Enable/disable theater mode"); addAction(theStrings, StMoviePlayer::Action_ShowGUI, "DoShowGUI", "Show/hide GUI");
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/StVideo/StVideo.h
Changed
@@ -164,6 +164,11 @@ ST_LOCAL void setStereoFormat(const StFormat theSrcFormat) { myVideoMaster->setStereoFormatByUser(theSrcFormat); } /** + * Get theater mode. + */ + ST_LOCAL bool isTheaterMode() const { return myVideoMaster->isTheaterMode(); } + + /** * Set theater mode. */ ST_LOCAL void setTheaterMode(bool theIsTheater) { myVideoMaster->setTheaterMode(theIsTheater); }
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/StVideo/StVideoQueue.h
Changed
@@ -194,6 +194,11 @@ } /** + * Get theater mode. + */ + ST_LOCAL bool isTheaterMode() const { return myIsTheaterMode; } + + /** * Set theater mode. */ ST_LOCAL void setTheaterMode(bool theIsTheater) {
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/chinese/StMoviePlayer.lng
Changed
@@ -265,4 +265,5 @@ ?6057=X Rotation - up ?6058=X Rotation - down ?6059=Enable/disable panorama mode -?6060=Show/hide GUI +?6060=Enable/disable theater mode +?6061=Show/hide GUI
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/chineset/StMoviePlayer.lng
Changed
@@ -265,4 +265,5 @@ 6057=X軸旋轉 - 上 6058=X軸旋轉 - 下 6059=開啟 / 關閉 環景模式 -6060=開啟 / 關閉 圖形化使用者介面 +6060=開啟 / 關閉 劇院模式 +6061=開啟 / 關閉 圖形化使用者介面
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/czech/StMoviePlayer.lng
Changed
@@ -266,4 +266,5 @@ ?6057=X Rotation - up ?6058=X Rotation - down ?6059=Enable/disable panorama mode -?6060=Show/hide GUI +?6060=Enable/disable theater mode +?6061=Show/hide GUI
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/english/StMoviePlayer.lng
Changed
@@ -265,4 +265,5 @@ 6057=X Rotation - up 6058=X Rotation - down 6059=Enable/disable panorama mode -6060=Show/hide GUI +6060=Enable/disable theater mode +6061=Show/hide GUI
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/french/StMoviePlayer.lng
Changed
@@ -265,4 +265,5 @@ ?6057=X Rotation - up ?6058=X Rotation - down 6059=Activer / désactiver le mode panorama -6060=Masquer l'interface +6060=Activer / désactiver le mode théâtre +6061=Masquer l'interface
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/german/StMoviePlayer.lng
Changed
@@ -265,4 +265,5 @@ 6057=X-Drehung - nach oben 6058=X-Drehung - nach unten 6059=Aktivieren / Deaktivieren der Panorama-Modus -6060=GUI ausblenden +6060=Aktivieren / Deaktivieren der Theater-Modus +6061=GUI ausblenden
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/korean/StMoviePlayer.lng
Changed
@@ -266,4 +266,5 @@ ?6057=X Rotation - up ?6058=X Rotation - down ?6059=Enable/disable panorama mode -?6060=Show/hide GUI +?6060=Enable/disable theater mode +?6061=Show/hide GUI
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/russian/StMoviePlayer.lng
Changed
@@ -266,4 +266,5 @@ 6057=X наклон - наверх 6058=X наклон - вниз 6059=Включить/выключить панорамный режим -6060=Скрыть интерфейс +6060=Включить/выключить театральный режим +6061=Скрыть интерфейс
View file
_service:obs_scm:sview-26.obscpio/StMoviePlayer/lang/spanish/StMoviePlayer.lng
Changed
@@ -264,4 +264,5 @@ 6057=Rotación X: arriba 6058=Rotación X: abajo 6059=Activar/Desactivar modo panorámico -6060=Mostrar/ocultar GUI +6060=Activar/Desactivar modo teatro +6061=Mostrar/ocultar GUI
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/StOutDistorted.cpp
Changed
@@ -56,6 +56,7 @@ STTR_PARAMETER_DISTORTION = 1120, STTR_PARAMETER_DISTORTION_OFF = 1121, STTR_PARAMETER_MONOCLONE = 1123, + STTR_PARAMETER_MIRROR_WINDOW = 1124, // about info STTR_PLUGIN_TITLE = 2000, @@ -170,11 +171,13 @@ } void StOutDistorted::getOptions(StParamsList& theList) const { - if(myDevice != DEVICE_HMD - && myDevice != DEVICE_S3DV) { + if (myDevice != DEVICE_HMD + && myDevice != DEVICE_S3DV) { theList.add(params.Layout); } - if(myDevice != DEVICE_HMD) { + if (myDevice == DEVICE_HMD) { + theList.add(params.MirrorWindow); + } else { theList.add(params.MonoClone); } } @@ -192,6 +195,7 @@ } params.MonoClone->setName(aLangMap.changeValueId(STTR_PARAMETER_MONOCLONE, "Show Mono in Stereo")); + params.MirrorWindow->setName(aLangMap.changeValueId(STTR_PARAMETER_MIRROR_WINDOW, "Mirror VR to window")); params.Layout->setName(aLangMap.changeValueId(STTR_PARAMETER_LAYOUT, "Layout")); params.Layout->defineOption(LAYOUT_SIDE_BY_SIDE_ANAMORPH, aLangMap.changeValueId(STTR_PARAMETER_LAYOUT_SBS_ANAMORPH, "Side-by-Side (Anamorph)")); @@ -321,6 +325,7 @@ // Distortion parameters params.MonoClone = new StBoolParamNamed(false, stCString("monoClone"), stCString("monoClone")); + params.MirrorWindow = new StBoolParamNamed(false, stCString("mirrorWindow"), stCString("mirrorWindow")); // Layout option params.Layout = new StEnumParam(myCanHdmiPack ? LAYOUT_OVER_UNDER : LAYOUT_SIDE_BY_SIDE_ANAMORPH, stCString("layout"), stCString("layout")); updateStrings(); @@ -334,6 +339,7 @@ StWindow::setPlacement(aRect, true); } mySettings->loadParam(params.MonoClone); + mySettings->loadParam(params.MirrorWindow); mySettings->loadParam(params.Layout); checkHdmiPack(); StWindow::setTitle("sView - Distorted Renderer"); @@ -380,6 +386,7 @@ mySettings->saveParam(params.Layout); mySettings->saveParam(params.MonoClone); + mySettings->saveParam(params.MirrorWindow); mySettings->saveFloatVec4(ST_SETTING_WARP_COEF, myBarrelCoef); mySettings->saveFloatVec4(ST_SETTING_CHROME_AB, myChromAb); if(myWasUsed) { @@ -898,7 +905,36 @@ // real screen buffer myContext->stglBindFramebuffer(StGLFrameBuffer::NO_FRAMEBUFFER); - if(hasComposError || myVrToDrawMsg || myVrMsgTimer.getElapsedTimeInSec() > 2.0) { + if (!hasComposError && params.MirrorWindow->getValue()) { + // the rendering into window in parallel of VR is undesired, + // as it might add some lags... + myContext->stglResizeViewport(aVPBoth); + myContext->stglResetScissorRect(); + myContext->core20fwd->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + const GLfloat aDX = GLfloat(myFrBuffer->getVPSizeX()) / GLfloat(myFrBuffer->getSizeX()); + const GLfloat aDY = GLfloat(myFrBuffer->getVPSizeY()) / GLfloat(myFrBuffer->getSizeY()); + StArray<StGLVec2> aTCoords(4); + aTCoords0 = StGLVec2(aDX, 0.0f); + aTCoords1 = StGLVec2(aDX, aDY); + aTCoords2 = StGLVec2(0.0f, 0.0f); + aTCoords3 = StGLVec2(0.0f, aDY); + myFrTCrdsBuf.init(*myContext, aTCoords); + + myFrBuffer->bindTexture(*myContext); + myProgramFlat->use(*myContext); + myFrVertsBuf.bindVertexAttrib(*myContext, myProgramFlat->getVVertexLoc()); + myFrTCrdsBuf.bindVertexAttrib(*myContext, myProgramFlat->getVTexCoordLoc()); + + myContext->core20fwd->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + myFrTCrdsBuf.unBindVertexAttrib(*myContext, myProgramFlat->getVTexCoordLoc()); + myFrVertsBuf.unBindVertexAttrib(*myContext, myProgramFlat->getVVertexLoc()); + myProgramFlat->unuse(*myContext); + myFrBuffer->unbindTexture(*myContext); + + StWindow::stglSwap(ST_WIN_ALL); + } else if (hasComposError || myVrToDrawMsg || myVrMsgTimer.getElapsedTimeInSec() > 2.0) { myContext->stglResizeViewport(aVPBoth); myContext->stglResetScissorRect(); myContext->core20fwd->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/StOutDistorted.h
Changed
@@ -268,6 +268,7 @@ StHandle<StEnumParam> Layout; //!< pair layout StHandle<StBoolParamNamed> MonoClone;//!< display mono in stereo + StHandle<StBoolParamNamed> MirrorWindow;//!< mirror VR fullscreen content to window } params;
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/chinese/StOutDistorted.lng
Changed
@@ -13,6 +13,7 @@ 1120=扭曲 1121=无 1123=单画面 +?1124=Mirror VR to window 2000=sView -变形输出模块 2001=版本 ?2002=© {0} Kirill Gavrilov Tartynskih <{1}>\nOfficial site: {2}
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/chineset/StOutDistorted.lng
Changed
@@ -13,6 +13,7 @@ 1120=扭曲變形 1121=無 1123=在立體模式顯示單通道 +?1124=Mirror VR to window 2000=sView - 扭曲變形輸出模組 2001=版本 2002=© {0} 基里爾·加夫里洛夫 Kirill Gavrilov Tartynskih <{1}>\n官方網站: {2}
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/czech/StOutDistorted.lng
Changed
@@ -14,6 +14,7 @@ 1120=Filtr 1121=Žádný 1123=Zobrazit mono ve stereu +?1124=Mirror VR to window 2000=sView - Modul deformace výstupu 2001=verze 2002=© {0} Гаврилов Кирилл <{1}>\nОфициальный сайт: {2}
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/english/StOutDistorted.lng
Changed
@@ -13,6 +13,7 @@ 1120=Distortion 1121=None 1123=Show Mono in Stereo +1124=Mirror VR to window 2000=sView - Distorted Output module 2001=version 2002=© {0} Kirill Gavrilov Tartynskih <{1}>\nOfficial site: {2}
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/french/StOutDistorted.lng
Changed
@@ -13,6 +13,7 @@ 1120=Distortion 1121=None 1123=Show Mono in Stereo +?1124=Mirror VR to window 2000=sView - Distorted Output module 2001=version 2002=© {0} Kirill Gavrilov Tartynskih <{1}>\nSite Officiel: {2}
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/german/StOutDistorted.lng
Changed
@@ -13,6 +13,7 @@ 1120=Verzerrung 1121=keiner 1123=Show Mono in Stereo +?1124=Mirror VR to window 2000=sView - Distorted Ausgangsmodul 2001=Version ?2002=© {0} Kirill Gavrilov Tartynskih <{1}>\nOfficial site: {2}
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/korean/StOutDistorted.lng
Changed
@@ -13,6 +13,7 @@ ?1120=Distortion ?1121=None ?1123=Show Mono in Stereo +?1124=Mirror VR to window ?2000=sView - Distorted Output module ?2001=version ?2002=© {0} Kirill Gavrilov Tartynskih <{1}>\nOfficial site: {2}
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/russian/StOutDistorted.lng
Changed
@@ -13,6 +13,7 @@ 1120=Фильтр 1121=None 1123=Отображать моно в стерео +1124=Зеркалировать VR в окне 2000=sView - Distorted Output module 2001=версия 2002=© {0} Гаврилов Кирилл <{1}>\nОфициальный сайт: {2}
View file
_service:obs_scm:sview-26.obscpio/StOutDistorted/lang/spanish/StOutDistorted.lng
Changed
@@ -12,6 +12,7 @@ 1120=Distorsión 1121=Ninguna 1123=Mostrar mono en estéreo +?1124=Mirror VR to window 2000=sView - Módulo de salida distorsionada 2001=versión 2002=© {0} Kirill Gavrilov Tartynskih <{1}>\nSitio oficial: {2}
View file
_service:obs_scm:sview-26.obscpio/StShared/CMakeLists.txt
Changed
@@ -1,63 +1,74 @@ project (StShared) set (USED_SRCFILES - StAVFrame.cpp - StAVImage.cpp - StAVIOContext.cpp - StAVIOFileContext.cpp - StAVIOJniHttpContext.cpp - StAVIOMemContext.cpp - StAVPacket.cpp - StAVVideoMuxer.cpp + StAV/stAV.cpp + StAV/StAVFrame.cpp + StAV/StAVImage.cpp + StAV/StAVIOContext.cpp + StAV/StAVIOFileContext.cpp + StAV/StAVIOJniHttpContext.cpp + StAV/StAVIOMemContext.cpp + StAV/StAVPacket.cpp + StAV/StAVVideoMuxer.cpp + StFile/StFileNode.cpp + StFile/StFileNode2.cpp + StFile/StFolder.cpp + StFile/StRawFile.cpp + StFT/StFTFont.cpp + StFT/StFTFontRegistry.cpp + StFT/StFTLibrary.cpp + StGL/StGLCircle.cpp + StGL/StGLContext.cpp + StGL/StGLFont.cpp + StGL/StGLFontEntry.cpp + StGL/StGLFontManager.cpp + StGL/StGLFrameBuffer.cpp + StGL/StGLMatrix.cpp + StGL/StGLMesh.cpp + StGL/StGLPrism.cpp + StGL/StGLProgram.cpp + StGL/StGLProjCamera.cpp + StGL/StGLQuadTexture.cpp + StGL/StGLQuads.cpp + StGL/StGLResource.cpp + StGL/StGLShader.cpp + StGL/StGLStereoFrameBuffer.cpp + StGL/StGLTextFormatter.cpp + StGL/StGLTexture.cpp + StGL/StGLTextureData.cpp + StGL/StGLTextureQueue.cpp + StGL/StGLUVCylinder.cpp + StGL/StGLUVSphere.cpp + StGL/StGLVertexBuffer.cpp + StImage/StDevILImage.cpp + StImage/StExifDir.cpp + StImage/StExifTags.cpp + StImage/StFreeImage.cpp + StImage/StImage.cpp + StImage/StImageFile.cpp + StImage/StImagePlane.cpp + StImage/StJpegParser.cpp + StImage/StNsImage.cpp + StImage/StStbImage.cpp + StImage/StWicImage.cpp + StSettings/StConfigImpl.cpp + StSettings/StRegisterImpl.cpp + StSettings/StSettings.cpp + StSettings/StTranslations.cpp + StStrings/stConsole.cpp + StStrings/StDictionary.cpp + StStrings/StLangMap.cpp + StStrings/StLogger.cpp + StStrings/stUtfTools.cpp StAction.cpp StBndBox.cpp StBndCameraBox.cpp StBndSphere.cpp StCondition.cpp - StConfigImpl.cpp - StDevILImage.cpp StEDIDParser.cpp - StExifDir.cpp - StExifTags.cpp - StFTFont.cpp - StFTFontRegistry.cpp - StFTLibrary.cpp - StFileNode.cpp - StFileNode2.cpp - StFolder.cpp StFormatEnum.cpp - StFreeImage.cpp - StGLCircle.cpp - StGLContext.cpp - StGLFont.cpp - StGLFontEntry.cpp - StGLFontManager.cpp - StGLFrameBuffer.cpp - StGLMatrix.cpp - StGLMesh.cpp - StGLPrism.cpp - StGLProgram.cpp - StGLProjCamera.cpp - StGLQuadTexture.cpp - StGLQuads.cpp - StGLResource.cpp - StGLShader.cpp - StGLStereoFrameBuffer.cpp - StGLTextFormatter.cpp - StGLTexture.cpp - StGLTextureData.cpp - StGLTextureQueue.cpp - StGLUVCylinder.cpp - StGLUVSphere.cpp - StGLVertexBuffer.cpp - StImage.cpp - StImageFile.cpp - StImagePlane.cpp StJNIEnv.cpp - StJpegParser.cpp - StLangMap.cpp StLibrary.cpp - StLogger.cpp StMinGen.cpp StMonitor.cpp StMsgQueue.cpp @@ -65,27 +76,19 @@ StPlayList.cpp StProcess.cpp StProcess2.cpp - StRawFile.cpp - StRegisterImpl.cpp StResourceManager.cpp - StSettings.cpp - StStbImage.cpp - StDictionary.cpp StThread.cpp - StTranslations.cpp StVirtualKeys.cpp - stAV.cpp - stConsole.cpp - stUtfTools.cpp ) set (USED_MMFILES + StFile/StFileNode.ObjC.mm + StImage/StNsImage.ObjC.mm + StSettings/StPListImpl.mm + StStrings/StLogger.ObjC.mm + StStrings/StStringUnicode.ObjC.mm StCocoaCoords.mm StCocoaLocalPool.mm - StFileNode.ObjC.mm - StLogger.ObjC.mm - StPListImpl.mm - StSocket.ObjC.mm - StStringUnicode.ObjC.mm + StProcess.ObjC.mm ) set (USED_INCFILES @@ -180,8 +183,10 @@ ../include/StImage/StImageFile.h ../include/StImage/StImagePlane.h ../include/StImage/StJpegParser.h + ../include/StImage/StNsImage.h ../include/StImage/StPixelRGB.h ../include/StImage/StStbImage.h + ../include/StImage/StWicImage.h ../include/StSettings/StEnumParam.h ../include/StSettings/StFloat32Param.h ../include/StSettings/StParam.h
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV
Added
+(directory)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/StAVFrame.cpp
Changed
(renamed from StShared/StAVFrame.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/StAVIOContext.cpp
Changed
(renamed from StShared/StAVIOContext.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/StAVIOFileContext.cpp
Changed
(renamed from StShared/StAVIOFileContext.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/StAVIOJniHttpContext.cpp
Changed
(renamed from StShared/StAVIOJniHttpContext.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/StAVIOMemContext.cpp
Changed
(renamed from StShared/StAVIOMemContext.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/StAVImage.cpp
Changed
(renamed from StShared/StAVImage.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/StAVPacket.cpp
Changed
(renamed from StShared/StAVPacket.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/StAVVideoMuxer.cpp
Changed
(renamed from StShared/StAVVideoMuxer.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StAV/stAV.cpp
Changed
(renamed from StShared/stAV.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StCocoaCoords.mm
Changed
@@ -11,54 +11,41 @@ #import <Cocoa/Cocoa.h> -StCocoaCoords::StCocoaCoords() -: myScreenBottom(0.0f), - myScale(1.0f), - myUnScale(1.0f) { +StCocoaCoords::StCocoaCoords() { init(); } bool StCocoaCoords::init() { - if(NSApp == nil) { + if (NSApp == nullptr) { return false; } + StCocoaLocalPool aLocalPool; NSArray* aScreens = NSScreen screens; - if(aScreens == NULL - || aScreens count == 0) { + if (aScreens == nullptr || aScreens count == 0) { return false; } NSScreen* aScreen = (NSScreen* )aScreens objectAtIndex: 0; - NSDictionary* aDict = aScreen deviceDescription; - NSNumber* aNumber = aDict objectForKey: @"NSScreenNumber"; - if(aNumber == NULL - || aNumber isKindOfClass: NSNumber class == NO) { - return false; - } - CGDirectDisplayID aDispId = aNumber unsignedIntValue; - CGRect aRect = CGDisplayBounds(aDispId); + const NSRect aRect = aScreen frame; myScreenBottom = aRect.origin.y + aRect.size.height; -ST_DISABLE_DEPRECATION_WARNINGS - myScale = aScreen userSpaceScaleFactor; -ST_ENABLE_DEPRECATION_WARNINGS - myUnScale = 1.0 / myScale; return true; } CGRect StCocoaCoords::normalToCocoa(const StRectI_t& theRectSt) const { return NSMakeRect(CGFloat(theRectSt.left()), myScreenBottom - CGFloat(theRectSt.bottom()), - CGFloat(theRectSt.width()) * myUnScale, - CGFloat(theRectSt.height()) * myUnScale); + CGFloat(theRectSt.width()), + CGFloat(theRectSt.height())); } StRectI_t StCocoaCoords::cocoaToNormal(const CGRect& theRectNs) const { - return StRectI_t(myScreenBottom - theRectNs.origin.y - theRectNs.size.height * myScale, - myScreenBottom - theRectNs.origin.y, + const CGFloat aBottom = myScreenBottom - theRectNs.origin.y; + return StRectI_t(aBottom - theRectNs.size.height, + aBottom, theRectNs.origin.x, - theRectNs.origin.x + theRectNs.size.width * myScale); + theRectNs.origin.x + theRectNs.size.width); } #endif // __APPLE__
View file
_service:obs_scm:sview-26.obscpio/StShared/StFT
Added
+(directory)
View file
_service:obs_scm:sview-26.obscpio/StShared/StFT/StFTFont.cpp
Changed
(renamed from StShared/StFTFont.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StFT/StFTFontRegistry.cpp
Added
@@ -0,0 +1,442 @@ +/** + * Copyright © 2013-2014 Kirill Gavrilov <kirill@sview.ru> + * + * This code is licensed under MIT license (see docs/license-mit.txt for details). + */ + +#include <StFT/StFTFontRegistry.h> + +#include <StFile/StFolder.h> +#include <StStrings/StLogger.h> +#include <StThreads/StProcess.h> +#include <stAssert.h> + +#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) + // use fontconfig library on Linux + #include <fontconfig/fontconfig.h> +#endif + +namespace { + static const StFTFontFamily THE_NO_FAMILY; +} + +StFTFontRegistry::StFTFontRegistry() { + myFTLib = new StFTLibrary(); + myExtensions.add("ttf"); + myExtensions.add("ttc"); + myExtensions.add("otf"); + + const StString aCustFontDir = StProcess::getStShareFolder() + "fonts" + SYS_FS_SPLITTER; + if(StFolder::isFolder(aCustFontDir)) { + myFolders.add(aCustFontDir); + } +#ifdef _WIN32 + myFolders.add(StProcess::getWindowsFolder() + "fonts"); + + // western + myFilesMajor.add(stCString("times.ttf")); + myFilesMajor.add(stCString("timesbd.ttf")); + myFilesMajor.add(stCString("timesi.ttf")); + myFilesMajor.add(stCString("timesbi.ttf")); + myFilesMajor.add(stCString("trebuc.ttf")); + myFilesMajor.add(stCString("trebucbd.ttf")); + myFilesMajor.add(stCString("trebucit.ttf")); + myFilesMajor.add(stCString("trebucbi.ttf")); + myFilesMajor.add(stCString("tahoma.ttf")); + myFilesMajor.add(stCString("tahomabd.ttf")); + myFilesMajor.add(stCString("micross.ttf")); + // korean + myFilesMajor.add(stCString("malgun.ttf")); + myFilesMajor.add(stCString("malgunbd.ttf")); + myFilesMinor.add(stCString("gulim.ttc")); // Win XP + myFilesMinor.add(stCString("gulim.ttf")); + // chinese + myFilesMajor.add(stCString("simsun.ttc")); +#elif defined(__APPLE__) + myExtensions.add("dfont"); + myFolders.add(stCString("/System/Library/Fonts")); + myFolders.add(stCString("/Library/Fonts")); + + // western + myFilesMinor.add(stCString("Times.dfont")); // old macOS + myFilesMajor.add(stCString("Times.ttc")); + myFilesMajor.add(stCString("Times New Roman.ttf")); + myFilesMajor.add(stCString("Times New Roman Bold.ttf")); + myFilesMajor.add(stCString("Times New Roman Italic.ttf")); + myFilesMajor.add(stCString("Times New Roman Bold Italic.ttf")); + myFilesMajor.add(stCString("Trebuchet MS.ttf")); + myFilesMajor.add(stCString("Trebuchet MS Bold.ttf")); + myFilesMajor.add(stCString("Trebuchet MS Italic.ttf")); + myFilesMajor.add(stCString("Trebuchet MS Bold Italic.ttf")); + myFilesMajor.add(stCString("Tahoma.ttf")); + myFilesMajor.add(stCString("Tahoma Bold.ttf")); + myFilesMinor.add(stCString("Monaco.dfont")); // old macOS + myFilesMajor.add(stCString("Monaco.ttf")); + // korean + //myFilesMajor.add(stCString("AppleMyungjo.ttf")); + myFilesMajor.add(stCString("AppleGothic.ttf")); + // chinese + myFilesMinor.add(stCString("华文仿宋.ttf")); // old macOS + myFilesMajor.add(stCString("Songti.ttc")); +#elif defined(__ANDROID__) + myFolders.add(stCString("/system/fonts")); + + // western + + // Android 6 + myFilesMajor.add(stCString("NotoSerif-Regular.ttf")); + myFilesMajor.add(stCString("NotoSerif-Bold.ttf")); + myFilesMajor.add(stCString("NotoSerif-Italic.ttf")); + myFilesMajor.add(stCString("NotoSerif-BoldItalic.ttf")); + + // Android 4 + myFilesMinor.add(stCString("DroidSerif-Regular.ttf")); + myFilesMinor.add(stCString("DroidSerif-Bold.ttf")); + myFilesMinor.add(stCString("DroidSerif-Italic.ttf")); + myFilesMinor.add(stCString("DroidSerif-BoldItalic.ttf")); + + myFilesMajor.add(stCString("DroidSans.ttf")); + myFilesMajor.add(stCString("DroidSans-Bold.ttf")); + myFilesMajor.add(stCString("DroidSansMono.ttf")); + + // not all phones have the following fonts + myFilesMinor.add(stCString("NotoSansCJK-Regular.ttc")); + + // Korean + myFilesMinor.add(stCString("NanumGothic.ttf")); + myFilesMinor.add(stCString("NotoSansKR-Regular.otf")); + + // Simplified Chinese + myFilesMinor.add(stCString("DroidSansFallback.ttf")); + myFilesMinor.add(stCString("NotoSansSC-Regular.otf")); + + // Traditional Chinese + //myFilesMinor.add(stCString("NotoSansTC-Regular.otf")); + + // Japanese + //myFilesMinor.add(stCString("NotoSansJP-Regular.otf")); + + // Arabic + myFilesMinor.add(stCString("NotoNaskhArabic-Regular.ttf")); + //myFilesMinor.add(stCString("NotoNaskhArabic-Bold.ttf")); +#else + +#if !defined(__EMSCRIPTEN__) + if(FcConfig* aFcCfg = FcInitLoadConfig()) { + if(FcStrList* aFcFontDir = FcConfigGetFontDirs(aFcCfg)) { + for(;;) { + FcChar8* aFcFolder = FcStrListNext(aFcFontDir); + if(aFcFolder == NULL) { + break; + } + + myFolders.add(StString((const char* )aFcFolder)); + } + FcStrListDone(aFcFontDir); + } + FcConfigDestroy(aFcCfg); + } +#endif + if(myFolders.isEmpty()) { + #ifdef APP_PREFIX + if(!StString(stCString(APP_PREFIX)).isEquals(stCString("/usr"))) { + myFolders.add(stCString(APP_PREFIX"/share/fonts")); + myFolders.add(stCString(APP_PREFIX"/local/share/fonts")); + } + #endif + myFolders.add(stCString("/usr/share/fonts")); + myFolders.add(stCString("/usr/local/share/fonts")); + } + + // western + myFilesMajor.add(stCString("DejaVuSerif.ttf")); + myFilesMajor.add(stCString("DejaVuSerif-Bold.ttf")); + myFilesMajor.add(stCString("DejaVuSans.ttf")); + myFilesMajor.add(stCString("DejaVuSans-Bold.ttf")); + myFilesMajor.add(stCString("DejaVuSansMono.ttf")); + myFilesMajor.add(stCString("DejaVuSansMono-Bold.ttf")); + + myFilesMajor.add(stCString("FreeSerif.ttf")); + myFilesMajor.add(stCString("FreeSerifBold.ttf")); + myFilesMajor.add(stCString("FreeSerifItalic.ttf")); + myFilesMajor.add(stCString("FreeSerifBoldItalic.ttf")); + myFilesMajor.add(stCString("FreeSans.ttf")); + myFilesMajor.add(stCString("FreeSansBold.ttf")); + myFilesMajor.add(stCString("FreeSansOblique.ttf")); + myFilesMajor.add(stCString("FreeSansBoldOblique.ttf")); + + // korean + myFilesMajor.add(stCString("NanumMyeongjo.ttf")); + myFilesMajor.add(stCString("NanumMyeongjoBold.ttf")); + myFilesMajor.add(stCString("NanumGothic.ttf")); + myFilesMajor.add(stCString("NanumGothicBold.ttf")); + myFilesMinor.add(stCString("NotoSerifCJK-Regular.ttc")); + + // chinese + //myFilesMajor.add(stCString("DroidSansJapanese.ttf")); + myFilesMajor.add(stCString("DroidSansFallbackFull.ttf")); +#endif +} + +StFTFontRegistry::~StFTFontRegistry() { + // +} + +void StFTFontRegistry::appendSearchPath(const StString& theFolder) { + myFolders.add(theFolder); +} + +bool StFTFontRegistry::registerFamily(const StString& theFontPath, int theFaceId) { + const FT_Long aFaceId = theFaceId != -1 ? theFaceId : 0; + FT_Face aFace = NULL; + if(FT_New_Face(myFTLib->getInstance(), theFontPath.toCString(), aFaceId, &aFace) != 0) { + if(aFace != NULL) { + FT_Done_Face(aFace); + } + return false; + } + if(aFace->family_name == NULL // skip broken fonts (error in FreeType?) + || FT_Select_Charmap(aFace, ft_encoding_unicode) != 0) { // handle only UNICODE fonts + FT_Done_Face(aFace); + return false; + } + + // generate font family name + StString aStyle(aFace->style_name != NULL ? aFace->style_name : ""); + { + // remove standard style combinations reflected by style_flags + // and keep only extra styles like Light, Condensed and similar + static const StString THE_EMPTY; + static const StString THE_SPACE1(" "); + static const StString THE_SPACE2(" "); + static const StString THE_ITALIC1("Italic"); + static const StString THE_ITALIC2("Oblique"); + static const StString THE_BOLD("Bold"); + static const StString THE_REGULAR1("Regular"); + static const StString THE_REGULAR2("Book"); + if(aFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) { + aStyle = aStyle.replace(THE_BOLD, THE_EMPTY); + const size_t aLen = aStyle.Length; + aStyle = aStyle.replace(THE_ITALIC1, THE_EMPTY); + if(aLen == aStyle.Length) { + aStyle = aStyle.replace(THE_ITALIC2, THE_EMPTY); + } + } else if(aFace->style_flags == FT_STYLE_FLAG_BOLD) { + aStyle = aStyle.replace(THE_BOLD, THE_EMPTY); + } else if(aFace->style_flags == FT_STYLE_FLAG_ITALIC) { + const size_t aLen = aStyle.Length; + aStyle = aStyle.replace(THE_ITALIC1, THE_EMPTY); + if(aLen == aStyle.Length) { + aStyle = aStyle.replace(THE_ITALIC2, THE_EMPTY); + } + } + const size_t aLen2 = aStyle.Length; + aStyle = aStyle.replace(THE_REGULAR1, THE_EMPTY); + if(aLen2 == aStyle.Length) { + aStyle = aStyle.replace(THE_REGULAR2, THE_EMPTY); + } + aStyle.leftAdjust(); + aStyle.rightAdjust(); + aStyle.replace(THE_SPACE2, THE_SPACE1); + } + + StString aFamilyName = aFace->family_name; + if(!aStyle.isEmpty()) { + aFamilyName = aFamilyName + " " + aStyle; + } + + StFTFontFamily& aFamily = myFontsaFamilyName; + aFamily.FamilyName = aFamilyName; + if(aFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) { + aFamily.BoldItalic = theFontPath; + aFamily.BoldItalicFace = (int )aFaceId; + } else if(aFace->style_flags == FT_STYLE_FLAG_BOLD) { + aFamily.Bold = theFontPath; + aFamily.BoldFace = (int )aFaceId; + } else if(aFace->style_flags == FT_STYLE_FLAG_ITALIC) { + aFamily.Italic = theFontPath; + aFamily.ItalicFace = (int )aFaceId; + } else { + aFamily.Regular = theFontPath; + aFamily.RegularFace = (int )aFaceId; + } + //ST_DEBUG_LOG("StFTFontRegistry, font file '" + theFontPath + " " + aFaceId + "" + "', family '" + aFamily.FamilyName + "', contains " + aFace->num_glyphs + " glyphs!"); + + if(theFaceId < aFace->num_faces) { + const FT_Long aNbInstances = aFace->style_flags >> 16; + for(FT_Long anInstIter = 1; anInstIter < aNbInstances; ++anInstIter) { + const FT_Long aSubFaceId = aFaceId + (anInstIter << 16); + registerFamily(theFontPath, aSubFaceId); + } + } + if(theFaceId == -1) { + for(FT_Long aFaceIter = 1; aFaceIter < aFace->num_faces; ++aFaceIter) { + registerFamily(theFontPath, aFaceIter); + } + } + FT_Done_Face(aFace); + return true; +} + +void StFTFontRegistry::searchFiles(const StArrayList<StString>& theNames, + const bool theIsMajor) { + for(size_t aNameIter = 0; aNameIter < theNames.size(); ++aNameIter) { + const StString& aName = theNames.getValue(aNameIter); + StString aPath; + if(StFileNode::isAbsolutePath(aName)) { + aPath = aName; + } else { + const StFileNode* aNode = myFoldersRoot.findValue(aName); + if(aNode != NULL) { + aPath = aNode->getPath(); + } + } + if(!StFileNode::isFileExists(aPath)) { + if(theIsMajor) { + ST_ERROR_LOG("StFTFontRegistry, major font file '" + aName + "' does not exist!"); + } + continue; + } + + if(!registerFamily(aPath, -1)) { + if(theIsMajor) { + ST_ERROR_LOG("StFTFontRegistry, major font file '" + aName + "' fail to load" + + " from path '" + aPath + "'!"); + } + continue; + } + } +} + +void StFTFontRegistry::init(const bool theToSearchAll) { + myFoldersRoot.clear(); + myFonts.clear(); + for(size_t aFolderIter = 0; aFolderIter < myFolders.size(); ++aFolderIter) { + StFolder* aSubFolder = new StFolder(myFolders.getValue(aFolderIter), &myFoldersRoot); + aSubFolder->init(myExtensions, 4); + myFoldersRoot.add(aSubFolder); + } + + searchFiles(myFilesMajor, true); + searchFiles(myFilesMinor, false); + + if(theToSearchAll) { + // + } + + StFTFontPack& aSerif = myTypefacesStFTFont::Typeface_Serif; + StFTFontPack& aSans = myTypefacesStFTFont::Typeface_SansSerif; + StFTFontPack& aMono = myTypefacesStFTFont::Typeface_Monospace; +#ifdef _WIN32 + aSerif.Western = findFont(stCString("Times New Roman")); + aSans .Western = findFont(stCString("Trebuchet MS")); + aMono .Western = findFont(stCString("Tahoma")); + aSans.MiscSymbols = aSerif.Western; // Trebuchet font does not include this sub-set + const StFTFontFamily& aMalgun = findFont(stCString("Malgun Gothic")); + const StFTFontFamily& aGulim = findFont(stCString("Gulim")); + const StFTFontFamily& aKor = aMalgun.FamilyName.isEmpty() && !aGulim.FamilyName.isEmpty() + ? aGulim + : aMalgun; + const StFTFontFamily& anArabic = findFont(stCString("Times New Roman")); + aSerif.Arabic = anArabic; + aSans .Arabic = anArabic; + aMono .Arabic = anArabic; + aSerif.Korean = aKor; + aSans .Korean = aKor; + aMono .Korean = aKor; + const StFTFontFamily& aSimSun = findFont(stCString("SimSun")); + aSerif.CJK = aSimSun; + aSans .CJK = aSimSun; + aMono .CJK = aSimSun; +#elif defined(__APPLE__) + aSerif.Western = findFont(stCString("Times New Roman")); + aSans .Western = findFont(stCString("Trebuchet MS")); + aMono .Western = findFont(stCString("Monaco")); + aSerif.Korean = findFont(stCString("AppleGothic")); // AppleMyungjo can not be loaded + aSans .Korean = findFont(stCString("AppleGothic")); + aMono .Korean = findFont(stCString("AppleGothic")); + const StFTFontFamily& aSongtiSC = findFont(stCString("Songti SC Light")); + const StFTFontFamily& aFang = findFont(stCString("STFangsong")); + const StFTFontFamily& aCjk = aSongtiSC.FamilyName.isEmpty() && !aFang.FamilyName.isEmpty() + ? aFang + : aSongtiSC; + aSerif.CJK = aCjk; + aSans .CJK = aCjk; + aMono .CJK = aCjk; + aSerif.Arabic = findFont(stCString("DecoType Naskh")); + aSans .Arabic = findFont(stCString("DecoType Naskh")); + aMono .Arabic = findFont(stCString("DecoType Naskh")); +#elif defined(__ANDROID__) + aSerif.Western = findFont(stCString("Noto Serif")); + if(aSerif.Western.FamilyName.isEmpty()) { + aSerif.Western = findFont(stCString("Droid Serif")); + } + aSans .Western = findFont(stCString("Roboto")); // actually DroidSans.ttf + aMono .Western = findFont(stCString("Droid Sans Mono")); + + aSerif.Korean = findFont(stCString("NanumGothic")); // no serif + aSans .Korean = aSerif.Korean; + aMono .Korean = aSerif.Korean; + if(aSerif.Korean.FamilyName.isEmpty()) { + aSerif.Korean = findFont(stCString("Noto Sans KR")); + aSans .Korean = aSerif.Korean; + aMono .Korean = aSerif.Korean; + } + aSerif.CJK = findFont(stCString("Droid Sans Fallback")); + aSans .CJK = aSerif.CJK; + aMono .CJK = aSerif.CJK; + if(aSerif.CJK.FamilyName.isEmpty()) { + aSerif.CJK = findFont(stCString("Noto Sans SC")); + aSans .CJK = aSerif.CJK; + aMono .CJK = aSerif.CJK; + } + if(aSerif.CJK.FamilyName.isEmpty()) { + aSerif.CJK = findFont(stCString("Noto Sans CJK JP")); + aSans .CJK = aSerif.CJK; + aMono .CJK = aSerif.CJK; + } + if(aSerif.Korean.FamilyName.isEmpty()) { + aSerif.Korean = aSerif.CJK; + aSans .Korean = aSerif.CJK; + aMono .Korean = aSerif.CJK; + } + + aSerif.Arabic = findFont(stCString("Droid Arabic Naskh")); + aSans .Arabic = aSerif.Arabic; + aMono .Arabic = aSerif.Arabic; + if(aSerif.Arabic.FamilyName.isEmpty()) { + aSerif.Arabic = findFont(stCString("Noto Naskh Arabic")); + aSans .Arabic = aSerif.Arabic; + aMono .Arabic = aSerif.Arabic; + } +#else + aSerif.Western = findFont(stCString("FreeSerif")); + aSans .Western = findFont(stCString("FreeSans")); + if(aSerif.Western.FamilyName.isEmpty()) { + aSerif.Western = findFont(stCString("DejaVu Serif")); + aSans .Western = findFont(stCString("DejaVu Sans")); + } + aMono .Western = findFont(stCString("DejaVu Sans Mono")); + + const StFTFontFamily& aNanumMyeon = findFont(stCString("NanumMyeongjo")); + const StFTFontFamily& aNotoSerifCjkJp = findFont(stCString("Noto Serif CJK JP")); + const StFTFontFamily& aNanumGoth = findFont(stCString("NanumGothic")); + aSerif.Korean = aNanumMyeon.FamilyName.isEmpty() && !aNotoSerifCjkJp.FamilyName.isEmpty() + ? aNotoSerifCjkJp + : aNanumMyeon;; + aSans .Korean = aNanumGoth.FamilyName.isEmpty() && !aNotoSerifCjkJp.FamilyName.isEmpty() + ? aNotoSerifCjkJp + : aNanumGoth; + aMono .Korean = aSans.Korean; + aSerif.CJK = findFont(stCString("Droid Sans Fallback")); + aSans .CJK = findFont(stCString("Droid Sans Fallback")); + aMono .CJK = findFont(stCString("Droid Sans Fallback")); +#endif +} + +const StFTFontFamily& StFTFontRegistry::findFont(const StCString& theFamily) { + std::map<StString, StFTFontFamily>::iterator anIter = myFonts.find(theFamily.toCString()); + return anIter != myFonts.end() + ? anIter->second + : THE_NO_FAMILY; +}
View file
_service:obs_scm:sview-26.obscpio/StShared/StFT/StFTLibrary.cpp
Changed
(renamed from StShared/StFTLibrary.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StFTFontRegistry.cpp
Deleted
@@ -1,441 +0,0 @@ -/** - * Copyright © 2013-2014 Kirill Gavrilov <kirill@sview.ru> - * - * This code is licensed under MIT license (see docs/license-mit.txt for details). - */ - -#include <StFT/StFTFontRegistry.h> - -#include <StFile/StFolder.h> -#include <StStrings/StLogger.h> -#include <StThreads/StProcess.h> -#include <stAssert.h> - -#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) - // use fontconfig library on Linux - #include <fontconfig/fontconfig.h> -#endif - -namespace { - static const StFTFontFamily THE_NO_FAMILY; -} - -StFTFontRegistry::StFTFontRegistry() { - myFTLib = new StFTLibrary(); - myExtensions.add("ttf"); - myExtensions.add("ttc"); - myExtensions.add("otf"); - - const StString aCustFontDir = StProcess::getStShareFolder() + "fonts" + SYS_FS_SPLITTER; - if(StFolder::isFolder(aCustFontDir)) { - myFolders.add(aCustFontDir); - } -#ifdef _WIN32 - myFolders.add(StProcess::getWindowsFolder() + "fonts"); - - // western - myFilesMajor.add(stCString("times.ttf")); - myFilesMajor.add(stCString("timesbd.ttf")); - myFilesMajor.add(stCString("timesi.ttf")); - myFilesMajor.add(stCString("timesbi.ttf")); - myFilesMajor.add(stCString("trebuc.ttf")); - myFilesMajor.add(stCString("trebucbd.ttf")); - myFilesMajor.add(stCString("trebucit.ttf")); - myFilesMajor.add(stCString("trebucbi.ttf")); - myFilesMajor.add(stCString("tahoma.ttf")); - myFilesMajor.add(stCString("tahomabd.ttf")); - myFilesMajor.add(stCString("micross.ttf")); - // korean - myFilesMajor.add(stCString("malgun.ttf")); - myFilesMajor.add(stCString("malgunbd.ttf")); - myFilesMinor.add(stCString("gulim.ttc")); // Win XP - myFilesMinor.add(stCString("gulim.ttf")); - // chinese - myFilesMajor.add(stCString("simsun.ttc")); -#elif defined(__APPLE__) - myExtensions.add("dfont"); - myFolders.add(stCString("/System/Library/Fonts")); - myFolders.add(stCString("/Library/Fonts")); - - // western - myFilesMinor.add(stCString("Times.dfont")); // old macOS - myFilesMajor.add(stCString("Times.ttc")); - myFilesMajor.add(stCString("Times New Roman.ttf")); - myFilesMajor.add(stCString("Times New Roman Bold.ttf")); - myFilesMajor.add(stCString("Times New Roman Italic.ttf")); - myFilesMajor.add(stCString("Times New Roman Bold Italic.ttf")); - myFilesMajor.add(stCString("Trebuchet MS.ttf")); - myFilesMajor.add(stCString("Trebuchet MS Bold.ttf")); - myFilesMajor.add(stCString("Trebuchet MS Italic.ttf")); - myFilesMajor.add(stCString("Trebuchet MS Bold Italic.ttf")); - myFilesMajor.add(stCString("Tahoma.ttf")); - myFilesMajor.add(stCString("Tahoma Bold.ttf")); - myFilesMajor.add(stCString("Monaco.dfont")); - // korean - //myFilesMajor.add(stCString("AppleMyungjo.ttf")); - myFilesMajor.add(stCString("AppleGothic.ttf")); - // chinese - myFilesMinor.add(stCString("华文仿宋.ttf")); // old macOS - myFilesMajor.add(stCString("Songti.ttc")); -#elif defined(__ANDROID__) - myFolders.add(stCString("/system/fonts")); - - // western - - // Android 6 - myFilesMajor.add(stCString("NotoSerif-Regular.ttf")); - myFilesMajor.add(stCString("NotoSerif-Bold.ttf")); - myFilesMajor.add(stCString("NotoSerif-Italic.ttf")); - myFilesMajor.add(stCString("NotoSerif-BoldItalic.ttf")); - - // Android 4 - myFilesMinor.add(stCString("DroidSerif-Regular.ttf")); - myFilesMinor.add(stCString("DroidSerif-Bold.ttf")); - myFilesMinor.add(stCString("DroidSerif-Italic.ttf")); - myFilesMinor.add(stCString("DroidSerif-BoldItalic.ttf")); - - myFilesMajor.add(stCString("DroidSans.ttf")); - myFilesMajor.add(stCString("DroidSans-Bold.ttf")); - myFilesMajor.add(stCString("DroidSansMono.ttf")); - - // not all phones have the following fonts - myFilesMinor.add(stCString("NotoSansCJK-Regular.ttc")); - - // Korean - myFilesMinor.add(stCString("NanumGothic.ttf")); - myFilesMinor.add(stCString("NotoSansKR-Regular.otf")); - - // Simplified Chinese - myFilesMinor.add(stCString("DroidSansFallback.ttf")); - myFilesMinor.add(stCString("NotoSansSC-Regular.otf")); - - // Traditional Chinese - //myFilesMinor.add(stCString("NotoSansTC-Regular.otf")); - - // Japanese - //myFilesMinor.add(stCString("NotoSansJP-Regular.otf")); - - // Arabic - myFilesMinor.add(stCString("NotoNaskhArabic-Regular.ttf")); - //myFilesMinor.add(stCString("NotoNaskhArabic-Bold.ttf")); -#else - -#if !defined(__EMSCRIPTEN__) - if(FcConfig* aFcCfg = FcInitLoadConfig()) { - if(FcStrList* aFcFontDir = FcConfigGetFontDirs(aFcCfg)) { - for(;;) { - FcChar8* aFcFolder = FcStrListNext(aFcFontDir); - if(aFcFolder == NULL) { - break; - } - - myFolders.add(StString((const char* )aFcFolder)); - } - FcStrListDone(aFcFontDir); - } - FcConfigDestroy(aFcCfg); - } -#endif - if(myFolders.isEmpty()) { - #ifdef APP_PREFIX - if(!StString(stCString(APP_PREFIX)).isEquals(stCString("/usr"))) { - myFolders.add(stCString(APP_PREFIX"/share/fonts")); - myFolders.add(stCString(APP_PREFIX"/local/share/fonts")); - } - #endif - myFolders.add(stCString("/usr/share/fonts")); - myFolders.add(stCString("/usr/local/share/fonts")); - } - - // western - myFilesMajor.add(stCString("DejaVuSerif.ttf")); - myFilesMajor.add(stCString("DejaVuSerif-Bold.ttf")); - myFilesMajor.add(stCString("DejaVuSans.ttf")); - myFilesMajor.add(stCString("DejaVuSans-Bold.ttf")); - myFilesMajor.add(stCString("DejaVuSansMono.ttf")); - myFilesMajor.add(stCString("DejaVuSansMono-Bold.ttf")); - - myFilesMajor.add(stCString("FreeSerif.ttf")); - myFilesMajor.add(stCString("FreeSerifBold.ttf")); - myFilesMajor.add(stCString("FreeSerifItalic.ttf")); - myFilesMajor.add(stCString("FreeSerifBoldItalic.ttf")); - myFilesMajor.add(stCString("FreeSans.ttf")); - myFilesMajor.add(stCString("FreeSansBold.ttf")); - myFilesMajor.add(stCString("FreeSansOblique.ttf")); - myFilesMajor.add(stCString("FreeSansBoldOblique.ttf")); - - // korean - myFilesMajor.add(stCString("NanumMyeongjo.ttf")); - myFilesMajor.add(stCString("NanumMyeongjoBold.ttf")); - myFilesMajor.add(stCString("NanumGothic.ttf")); - myFilesMajor.add(stCString("NanumGothicBold.ttf")); - myFilesMinor.add(stCString("NotoSerifCJK-Regular.ttc")); - - // chinese - //myFilesMajor.add(stCString("DroidSansJapanese.ttf")); - myFilesMajor.add(stCString("DroidSansFallbackFull.ttf")); -#endif -} - -StFTFontRegistry::~StFTFontRegistry() { - // -} - -void StFTFontRegistry::appendSearchPath(const StString& theFolder) { - myFolders.add(theFolder); -} - -bool StFTFontRegistry::registerFamily(const StString& theFontPath, int theFaceId) { - const FT_Long aFaceId = theFaceId != -1 ? theFaceId : 0; - FT_Face aFace = NULL; - if(FT_New_Face(myFTLib->getInstance(), theFontPath.toCString(), aFaceId, &aFace) != 0) { - if(aFace != NULL) { - FT_Done_Face(aFace); - } - return false; - } - if(aFace->family_name == NULL // skip broken fonts (error in FreeType?) - || FT_Select_Charmap(aFace, ft_encoding_unicode) != 0) { // handle only UNICODE fonts - FT_Done_Face(aFace); - return false; - } - - // generate font family name - StString aStyle(aFace->style_name != NULL ? aFace->style_name : ""); - { - // remove standard style combinations reflected by style_flags - // and keep only extra styles like Light, Condensed and similar - static const StString THE_EMPTY; - static const StString THE_SPACE1(" "); - static const StString THE_SPACE2(" "); - static const StString THE_ITALIC1("Italic"); - static const StString THE_ITALIC2("Oblique"); - static const StString THE_BOLD("Bold"); - static const StString THE_REGULAR1("Regular"); - static const StString THE_REGULAR2("Book"); - if(aFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) { - aStyle = aStyle.replace(THE_BOLD, THE_EMPTY); - const size_t aLen = aStyle.Length; - aStyle = aStyle.replace(THE_ITALIC1, THE_EMPTY); - if(aLen == aStyle.Length) { - aStyle = aStyle.replace(THE_ITALIC2, THE_EMPTY); - } - } else if(aFace->style_flags == FT_STYLE_FLAG_BOLD) { - aStyle = aStyle.replace(THE_BOLD, THE_EMPTY); - } else if(aFace->style_flags == FT_STYLE_FLAG_ITALIC) { - const size_t aLen = aStyle.Length; - aStyle = aStyle.replace(THE_ITALIC1, THE_EMPTY); - if(aLen == aStyle.Length) { - aStyle = aStyle.replace(THE_ITALIC2, THE_EMPTY); - } - } - const size_t aLen2 = aStyle.Length; - aStyle = aStyle.replace(THE_REGULAR1, THE_EMPTY); - if(aLen2 == aStyle.Length) { - aStyle = aStyle.replace(THE_REGULAR2, THE_EMPTY); - } - aStyle.leftAdjust(); - aStyle.rightAdjust(); - aStyle.replace(THE_SPACE2, THE_SPACE1); - } - - StString aFamilyName = aFace->family_name; - if(!aStyle.isEmpty()) { - aFamilyName = aFamilyName + " " + aStyle; - } - - StFTFontFamily& aFamily = myFontsaFamilyName; - aFamily.FamilyName = aFamilyName; - if(aFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD)) { - aFamily.BoldItalic = theFontPath; - aFamily.BoldItalicFace = (int )aFaceId; - } else if(aFace->style_flags == FT_STYLE_FLAG_BOLD) { - aFamily.Bold = theFontPath; - aFamily.BoldFace = (int )aFaceId; - } else if(aFace->style_flags == FT_STYLE_FLAG_ITALIC) { - aFamily.Italic = theFontPath; - aFamily.ItalicFace = (int )aFaceId; - } else { - aFamily.Regular = theFontPath; - aFamily.RegularFace = (int )aFaceId; - } - //ST_DEBUG_LOG("StFTFontRegistry, font file '" + theFontPath + " " + aFaceId + "" + "', family '" + aFamily.FamilyName + "', contains " + aFace->num_glyphs + " glyphs!"); - - if(theFaceId < aFace->num_faces) { - const FT_Long aNbInstances = aFace->style_flags >> 16; - for(FT_Long anInstIter = 1; anInstIter < aNbInstances; ++anInstIter) { - const FT_Long aSubFaceId = aFaceId + (anInstIter << 16); - registerFamily(theFontPath, aSubFaceId); - } - } - if(theFaceId == -1) { - for(FT_Long aFaceIter = 1; aFaceIter < aFace->num_faces; ++aFaceIter) { - registerFamily(theFontPath, aFaceIter); - } - } - FT_Done_Face(aFace); - return true; -} - -void StFTFontRegistry::searchFiles(const StArrayList<StString>& theNames, - const bool theIsMajor) { - for(size_t aNameIter = 0; aNameIter < theNames.size(); ++aNameIter) { - const StString& aName = theNames.getValue(aNameIter); - StString aPath; - if(StFileNode::isAbsolutePath(aName)) { - aPath = aName; - } else { - const StFileNode* aNode = myFoldersRoot.findValue(aName); - if(aNode != NULL) { - aPath = aNode->getPath(); - } - } - if(!StFileNode::isFileExists(aPath)) { - if(theIsMajor) { - ST_ERROR_LOG("StFTFontRegistry, major font file '" + aName + "' does not exist!"); - } - continue; - } - - if(!registerFamily(aPath, -1)) { - if(theIsMajor) { - ST_ERROR_LOG("StFTFontRegistry, major font file '" + aName + "' fail to load" - + " from path '" + aPath + "'!"); - } - continue; - } - } -} - -void StFTFontRegistry::init(const bool theToSearchAll) { - myFoldersRoot.clear(); - myFonts.clear(); - for(size_t aFolderIter = 0; aFolderIter < myFolders.size(); ++aFolderIter) { - StFolder* aSubFolder = new StFolder(myFolders.getValue(aFolderIter), &myFoldersRoot); - aSubFolder->init(myExtensions, 4); - myFoldersRoot.add(aSubFolder); - } - - searchFiles(myFilesMajor, true); - searchFiles(myFilesMinor, false); - - if(theToSearchAll) { - // - } - - StFTFontPack& aSerif = myTypefacesStFTFont::Typeface_Serif; - StFTFontPack& aSans = myTypefacesStFTFont::Typeface_SansSerif; - StFTFontPack& aMono = myTypefacesStFTFont::Typeface_Monospace; -#ifdef _WIN32 - aSerif.Western = findFont(stCString("Times New Roman")); - aSans .Western = findFont(stCString("Trebuchet MS")); - aMono .Western = findFont(stCString("Tahoma")); - aSans.MiscSymbols = aSerif.Western; // Trebuchet font does not include this sub-set - const StFTFontFamily& aMalgun = findFont(stCString("Malgun Gothic")); - const StFTFontFamily& aGulim = findFont(stCString("Gulim")); - const StFTFontFamily& aKor = aMalgun.FamilyName.isEmpty() && !aGulim.FamilyName.isEmpty() - ? aGulim - : aMalgun; - const StFTFontFamily& anArabic = findFont(stCString("Times New Roman")); - aSerif.Arabic = anArabic; - aSans .Arabic = anArabic; - aMono .Arabic = anArabic; - aSerif.Korean = aKor; - aSans .Korean = aKor; - aMono .Korean = aKor; - const StFTFontFamily& aSimSun = findFont(stCString("SimSun")); - aSerif.CJK = aSimSun; - aSans .CJK = aSimSun; - aMono .CJK = aSimSun; -#elif defined(__APPLE__) - aSerif.Western = findFont(stCString("Times New Roman")); - aSans .Western = findFont(stCString("Trebuchet MS")); - aMono .Western = findFont(stCString("Monaco")); - aSerif.Korean = findFont(stCString("AppleGothic")); // AppleMyungjo can not be loaded - aSans .Korean = findFont(stCString("AppleGothic")); - aMono .Korean = findFont(stCString("AppleGothic")); - const StFTFontFamily& aSongtiSC = findFont(stCString("Songti SC Light")); - const StFTFontFamily& aFang = findFont(stCString("STFangsong")); - const StFTFontFamily& aCjk = aSongtiSC.FamilyName.isEmpty() && !aFang.FamilyName.isEmpty() - ? aFang - : aSongtiSC; - aSerif.CJK = aCjk; - aSans .CJK = aCjk; - aMono .CJK = aCjk; - aSerif.Arabic = findFont(stCString("DecoType Naskh")); - aSans .Arabic = findFont(stCString("DecoType Naskh")); - aMono .Arabic = findFont(stCString("DecoType Naskh")); -#elif defined(__ANDROID__) - aSerif.Western = findFont(stCString("Noto Serif")); - if(aSerif.Western.FamilyName.isEmpty()) { - aSerif.Western = findFont(stCString("Droid Serif")); - } - aSans .Western = findFont(stCString("Roboto")); // actually DroidSans.ttf - aMono .Western = findFont(stCString("Droid Sans Mono")); - - aSerif.Korean = findFont(stCString("NanumGothic")); // no serif - aSans .Korean = aSerif.Korean; - aMono .Korean = aSerif.Korean; - if(aSerif.Korean.FamilyName.isEmpty()) { - aSerif.Korean = findFont(stCString("Noto Sans KR")); - aSans .Korean = aSerif.Korean; - aMono .Korean = aSerif.Korean; - } - aSerif.CJK = findFont(stCString("Droid Sans Fallback")); - aSans .CJK = aSerif.CJK; - aMono .CJK = aSerif.CJK; - if(aSerif.CJK.FamilyName.isEmpty()) { - aSerif.CJK = findFont(stCString("Noto Sans SC")); - aSans .CJK = aSerif.CJK; - aMono .CJK = aSerif.CJK; - } - if(aSerif.CJK.FamilyName.isEmpty()) { - aSerif.CJK = findFont(stCString("Noto Sans CJK JP")); - aSans .CJK = aSerif.CJK; - aMono .CJK = aSerif.CJK; - } - if(aSerif.Korean.FamilyName.isEmpty()) { - aSerif.Korean = aSerif.CJK; - aSans .Korean = aSerif.CJK; - aMono .Korean = aSerif.CJK; - } - - aSerif.Arabic = findFont(stCString("Droid Arabic Naskh")); - aSans .Arabic = aSerif.Arabic; - aMono .Arabic = aSerif.Arabic; - if(aSerif.Arabic.FamilyName.isEmpty()) { - aSerif.Arabic = findFont(stCString("Noto Naskh Arabic")); - aSans .Arabic = aSerif.Arabic; - aMono .Arabic = aSerif.Arabic; - } -#else - aSerif.Western = findFont(stCString("FreeSerif")); - aSans .Western = findFont(stCString("FreeSans")); - if(aSerif.Western.FamilyName.isEmpty()) { - aSerif.Western = findFont(stCString("DejaVu Serif")); - aSans .Western = findFont(stCString("DejaVu Sans")); - } - aMono .Western = findFont(stCString("DejaVu Sans Mono")); - - const StFTFontFamily& aNanumMyeon = findFont(stCString("NanumMyeongjo")); - const StFTFontFamily& aNotoSerifCjkJp = findFont(stCString("Noto Serif CJK JP")); - const StFTFontFamily& aNanumGoth = findFont(stCString("NanumGothic")); - aSerif.Korean = aNanumMyeon.FamilyName.isEmpty() && !aNotoSerifCjkJp.FamilyName.isEmpty() - ? aNotoSerifCjkJp - : aNanumMyeon;; - aSans .Korean = aNanumGoth.FamilyName.isEmpty() && !aNotoSerifCjkJp.FamilyName.isEmpty() - ? aNotoSerifCjkJp - : aNanumGoth; - aMono .Korean = aSans.Korean; - aSerif.CJK = findFont(stCString("Droid Sans Fallback")); - aSans .CJK = findFont(stCString("Droid Sans Fallback")); - aMono .CJK = findFont(stCString("Droid Sans Fallback")); -#endif -} - -const StFTFontFamily& StFTFontRegistry::findFont(const StCString& theFamily) { - std::map<StString, StFTFontFamily>::iterator anIter = myFonts.find(theFamily.toCString()); - return anIter != myFonts.end() - ? anIter->second - : THE_NO_FAMILY; -}
View file
_service:obs_scm:sview-26.obscpio/StShared/StFile
Added
+(directory)
View file
_service:obs_scm:sview-26.obscpio/StShared/StFile/StFileNode.ObjC.mm
Changed
(renamed from StShared/StFileNode.ObjC.mm)
View file
_service:obs_scm:sview-26.obscpio/StShared/StFile/StFileNode.cpp
Changed
(renamed from StShared/StFileNode.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StFile/StFileNode2.cpp
Changed
(renamed from StShared/StFileNode2.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StFile/StFolder.cpp
Changed
(renamed from StShared/StFolder.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StFile/StRawFile.cpp
Changed
(renamed from StShared/StRawFile.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL
Added
+(directory)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StDejaVuSerif.ttf.h
Changed
(renamed from StShared/StDejaVuSerif.ttf.h)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLCircle.cpp
Changed
(renamed from StShared/StGLCircle.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLContext.cpp
Changed
(renamed from StShared/StGLContext.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLFont.cpp
Changed
(renamed from StShared/StGLFont.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLFontEntry.cpp
Changed
(renamed from StShared/StGLFontEntry.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLFontManager.cpp
Changed
(renamed from StShared/StGLFontManager.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLFrameBuffer.cpp
Changed
(renamed from StShared/StGLFrameBuffer.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLMatrix.cpp
Changed
(renamed from StShared/StGLMatrix.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLMesh.cpp
Changed
(renamed from StShared/StGLMesh.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLPrism.cpp
Changed
(renamed from StShared/StGLPrism.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLProgram.cpp
Changed
(renamed from StShared/StGLProgram.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLProjCamera.cpp
Changed
(renamed from StShared/StGLProjCamera.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLQuadTexture.cpp
Changed
(renamed from StShared/StGLQuadTexture.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLQuads.cpp
Changed
(renamed from StShared/StGLQuads.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLResource.cpp
Changed
(renamed from StShared/StGLResource.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLShader.cpp
Changed
(renamed from StShared/StGLShader.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLStereoFrameBuffer.cpp
Changed
(renamed from StShared/StGLStereoFrameBuffer.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLTextFormatter.cpp
Changed
(renamed from StShared/StGLTextFormatter.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLTexture.cpp
Changed
(renamed from StShared/StGLTexture.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLTextureData.cpp
Changed
(renamed from StShared/StGLTextureData.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLTextureQueue.cpp
Changed
(renamed from StShared/StGLTextureQueue.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLUVCylinder.cpp
Changed
(renamed from StShared/StGLUVCylinder.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLUVSphere.cpp
Changed
(renamed from StShared/StGLUVSphere.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StGL/StGLVertexBuffer.cpp
Changed
(renamed from StShared/StGLVertexBuffer.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage
Added
+(directory)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StDevILImage.cpp
Changed
(renamed from StShared/StDevILImage.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StExifDir.cpp
Changed
(renamed from StShared/StExifDir.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StExifTags.cpp
Changed
(renamed from StShared/StExifTags.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StFreeImage.cpp
Changed
(renamed from StShared/StFreeImage.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StImage.cpp
Changed
(renamed from StShared/StImage.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StImageFile.cpp
Added
@@ -0,0 +1,337 @@ +/** + * Copyright © 2010-2022 Kirill Gavrilov <kirill@sview.ru> + * + * This code is licensed under MIT license (see docs/license-mit.txt for details). + */ + +#include <StImage/StImageFile.h> + +#include <StImage/StDevILImage.h> +#include <StImage/StFreeImage.h> +#include <StImage/StNsImage.h> +#include <StImage/StStbImage.h> +#include <StImage/StWicImage.h> +#include <StAV/StAVImage.h> +#include <StFile/StFileNode.h> +#include <StFile/StMIME.h> +#include <StFile/StRawFile.h> + +#include <StStrings/StLogger.h> + +/** + * DDS Pixel Format structure. + */ +struct StDDSPixelFormat { + uint32_t Size; + uint32_t Flags; + uint32_t FourCC; + uint32_t RGBBitCount; + uint32_t RBitMask; + uint32_t GBitMask; + uint32_t BBitMask; + uint32_t ABitMask; +}; + +/** + * DDS File header structure. + */ +struct StDDSFileHeader { + /** + * Caps2 flag indicating complete (6 faces) cubemap. + */ + enum { DDSCompleteCubemap = 0xFE00 }; + + /** + * Return TRUE if cubmap flag is set. + */ + bool isCompleteCubemap() const { return (Caps2 & DDSCompleteCubemap) != 0; } + + uint32_t Size; + uint32_t Flags; + uint32_t Height; + uint32_t Width; + uint32_t PitchOrLinearSize; + uint32_t Depth; + uint32_t MipMapCount; + uint32_t Reserved111; + StDDSPixelFormat PixelFormatDef; + uint32_t Caps; + uint32_t Caps2; + uint32_t Caps3; + uint32_t Caps4; + uint32_t Reserved2; +}; + +StImageFile::StImageFile() +: mySrcFormat(StFormat_AUTO), + mySrcPanorama(StPanorama_OFF) { + // +} + +StImageFile::~StImageFile() { + // +} + +StImageFile::ImageClass StImageFile::imgLibFromString(const StString& thePreferred) { + StImageFile::ImageClass aPreferred = ST_LIBAV; + if(thePreferred.isEqualsIgnoreCase(stCString("LibAV")) || + thePreferred.isEqualsIgnoreCase(stCString("FFmpeg")) || + thePreferred.isEqualsIgnoreCase(stCString("StAVImage"))) { + aPreferred = ST_LIBAV; + } else if(thePreferred.isEqualsIgnoreCase(stCString("FreeImage")) || + thePreferred.isEqualsIgnoreCase(stCString("StFreeImage"))) { + aPreferred = ST_FREEIMAGE; + } else if(thePreferred.isEqualsIgnoreCase(stCString("DevIL")) || + thePreferred.isEqualsIgnoreCase(stCString("StDevILImage"))) { + aPreferred = ST_DEVIL; + } else if(thePreferred.isEqualsIgnoreCase(stCString("stb"))) { + aPreferred = ST_STB; + } else if(thePreferred.isEqualsIgnoreCase(stCString("WIC")) || + thePreferred.isEqualsIgnoreCase(stCString("WinCodec")) || + thePreferred.isEqualsIgnoreCase(stCString("StWicImage"))) { + aPreferred = ST_WIC; + } else if(thePreferred.isEqualsIgnoreCase(stCString("NSImage")) || + thePreferred.isEqualsIgnoreCase(stCString("AppKit")) || + thePreferred.isEqualsIgnoreCase(stCString("StNsImage"))) { + aPreferred = ST_NSIMAGE; + } + return aPreferred; +} + +StString StImageFile::imgLibToString(const ImageClass thePreferred) { + switch(thePreferred) { + case ST_FREEIMAGE: return "FreeImage"; + case ST_DEVIL: return "DevIL"; + case ST_STB: return "stb"; + case ST_WIC: return "WIC"; + case ST_NSIMAGE: return "NSImage"; + default: + case ST_LIBAV: return "FFmpeg"; + } +} + +StImageFile::ImageType StImageFile::guessImageType(const StString& theFileName, + const StMIME& theMIMEType) { + StString anExt = !theMIMEType.isEmpty() ? theMIMEType.getExtension() : StFileNode::getExtension(theFileName); + if(anExt.isEqualsIgnoreCase(stCString("mpo")) + || theMIMEType.getMIMEType().isEquals(stCString("image/mpo")) + || theMIMEType.getMIMEType().isEquals(stCString("image/x-mpo"))) { + return StImageFile::ST_TYPE_MPO; + } else if(anExt.isEqualsIgnoreCase(stCString("jps")) + || theMIMEType.getMIMEType().isEquals(stCString("image/jps")) + || theMIMEType.getMIMEType().isEquals(stCString("image/x-jps"))) { + return StImageFile::ST_TYPE_JPS; + } else if(anExt.isEqualsIgnoreCase(stCString("pns")) + || theMIMEType.getMIMEType().isEquals(stCString("image/pns")) + || theMIMEType.getMIMEType().isEquals(stCString("image/x-pns"))) { + return StImageFile::ST_TYPE_PNS; + } else if(anExt.isEqualsIgnoreCase(stCString("jpg")) + || anExt.isEqualsIgnoreCase(stCString("jpeg")) + || anExt.isEqualsIgnoreCase(stCString("jpe")) + || theMIMEType.getMIMEType().isEquals(stCString("image/jpg")) + || theMIMEType.getMIMEType().isEquals(stCString("image/jpeg"))) { + return StImageFile::ST_TYPE_JPEG; + } else if(anExt.isEqualsIgnoreCase(stCString("png")) + || theMIMEType.getMIMEType().isEquals(stCString("image/png"))) { + return StImageFile::ST_TYPE_PNG; + } else if(anExt.isEqualsIgnoreCase(stCString("exr"))) { + return StImageFile::ST_TYPE_EXR; + } else if(anExt.isEqualsIgnoreCase(stCString("psd"))) { + return StImageFile::ST_TYPE_PSD; + } else if(anExt.isEqualsIgnoreCase(stCString("ico"))) { + return StImageFile::ST_TYPE_ICO; + } else if(anExt.isEqualsIgnoreCase(stCString("hdr"))) { + return StImageFile::ST_TYPE_HDR; + } else if(anExt.isEqualsIgnoreCase(stCString("webp")) + || theMIMEType.getMIMEType().isEquals(stCString("image/webp"))) { + return StImageFile::ST_TYPE_WEBP; + } else if(anExt.isEqualsIgnoreCase(stCString("webpll")) + || theMIMEType.getMIMEType().isEquals(stCString("image/webpll"))) { + return StImageFile::ST_TYPE_WEBPLL; + } else if(anExt.isEqualsIgnoreCase(stCString("dds")) + || theMIMEType.getMIMEType().isEquals(stCString("image/vnd-ms.dds"))) { + return StImageFile::ST_TYPE_DDS; + } + return StImageFile::ST_TYPE_NONE; +} + +StHandle<StImageFile> StImageFile::create(const StString& thePreferred, + ImageType theImgType) { + return StImageFile::create(imgLibFromString(thePreferred), theImgType); +} + +StHandle<StImageFile> StImageFile::create(StImageFile::ImageClass thePreferred, + ImageType theImgType) { + (void)theImgType; + // open requested library if it exists + switch(thePreferred) { + case ST_FREEIMAGE: { + if(StFreeImage::init()) { + return new StFreeImage(); + } + break; + } + case ST_DEVIL: { + if(StDevILImage::init()) { + return new StDevILImage(); + } + break; + } + case ST_STB: { + if(StStbImage::init()) { + return new StStbImage(); + } + break; + } + case ST_WIC: { + if(StWicImage::init()) { + return new StWicImage(); + } + break; + } + case ST_NSIMAGE: { + if(StNsImage::init()) { + return new StNsImage(); + } + break; + } + default: + case ST_LIBAV: { + if(StAVImage::init()) { + return new StAVImage(); + } + break; + } + } + + // use default library anyway (that currently always linked) + if(StAVImage::init()) { + return new StAVImage(); + } + return StHandle<StImageFile>(); +} + +bool StImageFile::load(const StString& theFilePath, + ImageType theImageType, + uint8_t* theDataPtr, int theDataSize) { + if(theImageType == ST_TYPE_DDS) { + // Most image libraries ignore arrays/cubemaps in DDS file. + // As DDS format is pretty simple - parse it here and load cubemap as vertically stacked image. + StRawFile aRawFile(theFilePath); + if(theDataPtr == NULL) { + if(!aRawFile.readFile()) { + return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); + } + theDataPtr = (uint8_t* )aRawFile.getBuffer(); + theDataSize = (int )aRawFile.getSize(); + } + + if (theDataSize < 128 + || memcmp (&theDataPtr0, "DDS ", 4) != 0) { + return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); + } + + const StDDSFileHeader* aSrcHeader = (const StDDSFileHeader* )&theDataPtr4; + if (aSrcHeader->Size != 124 + || aSrcHeader->Width == 0 + || aSrcHeader->Height == 0 + || aSrcHeader->Width != aSrcHeader->Height + || aSrcHeader->PixelFormatDef.Size != 32 + || (aSrcHeader->Caps2 & StDDSFileHeader::DDSCompleteCubemap) != StDDSFileHeader::DDSCompleteCubemap) { + return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); + } + + const int aHeaderSize = aSrcHeader->Size + 4; + const int aPayLoadSize = theDataSize - aHeaderSize; + if (aPayLoadSize % 6 != 0 + || aPayLoadSize <= 0) { + return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); + } + + const int aTileDataSize = aPayLoadSize / 6; + StArray<uint8_t> aTileBuffer (aTileDataSize + aHeaderSize); + memcpy(&aTileBuffer.changeFirst(), "DDS ", 4); + memcpy(&aTileBuffer.changeValue(4), aSrcHeader, aSrcHeader->Size); + StDDSFileHeader* aHeaderTile = (StDDSFileHeader* )&aTileBuffer.changeValue(4); + aHeaderTile->Caps2 &= ~(StDDSFileHeader::DDSCompleteCubemap); + + StHandle<StImageFile> aTileImage = createEmpty(); + + memcpy(&aTileBuffer.changeValue(aHeaderSize), &theDataPtraHeaderSize, aTileDataSize); + if(!aTileImage->loadExtra(theFilePath, theImageType, &aTileBuffer.changeFirst(), (int )aTileBuffer.size(), false) + || aTileImage->isNull() + || aTileImage->getSizeX() < 1 + || aTileImage->getSizeY() < 1 + || aTileImage->getSizeX() != aTileImage->getSizeY()) { + return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); + } + + close(); + nullify(); + myMetadata = aTileImage->myMetadata; + myStateDescr = aTileImage->myStateDescr; + mySrcFormat = aTileImage->mySrcFormat; + setColorModel(aTileImage->getColorModel()); + setColorScale(aTileImage->getColorScale()); + setPixelRatio(aTileImage->getPixelRatio()); + const bool isTopDownLayout = aTileImage->isTopDown(); + for(size_t aPlaneId = 0; aPlaneId < 4; ++aPlaneId) { + const StImagePlane& aFromPlane = aTileImage->getPlane(aPlaneId); + const size_t aTileIndex = isTopDownLayout ? 0 : 5; + if(!aFromPlane.isNull()) { + if(!changePlane(aPlaneId).initTrash(aFromPlane.getFormat(), aFromPlane.getSizeX(), aFromPlane.getSizeX() * 6)) { + return false; + } + changePlane(aPlaneId).setTopDown(aFromPlane.isTopDown()); + memcpy(changePlane(aPlaneId).changeData() + aFromPlane.getSizeBytes() * aTileIndex, + aFromPlane.getData(), aFromPlane.getSizeBytes()); + } + } + + for(size_t aTileIter = 1; aTileIter < 6; ++aTileIter) { + memcpy(&aTileBuffer.changeValue(aHeaderSize), &theDataPtraTileIter * aTileDataSize + aHeaderSize, aTileDataSize); + aTileImage = createEmpty(); + if(!aTileImage->loadExtra(theFilePath, theImageType, &aTileBuffer.changeFirst(), (int )aTileBuffer.size(), false) + || aTileImage->isNull() + || aTileImage->getSizeX() != getSizeX() + || aTileImage->getSizeY() != getSizeX() // square + || aTileImage->getColorModel() != getColorModel() + || aTileImage->getPlane().getFormat() != getPlane().getFormat()) { + ST_ERROR_LOG("Internal error: DDS file is decoded into inconsistent tiles"); + return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); + } + + const size_t aTileIndex = isTopDownLayout ? aTileIter : (5 - aTileIter); + for(size_t aPlaneId = 0; aPlaneId < 4; ++aPlaneId) { + const StImagePlane& aFromPlane = aTileImage->getPlane(aPlaneId); + if(!aFromPlane.isNull()) { + memcpy(changePlane(aPlaneId).changeData() + aFromPlane.getSizeBytes() * aTileIndex, + aFromPlane.getData(), aFromPlane.getSizeBytes()); + } + } + } + mySrcPanorama = StPanorama_Cubemap1_6; + return true; + } + return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); +} + +StImageFileCounter::StImageFileCounter() {} + +StImageFileCounter::StImageFileCounter(const StHandle<StImage>& theImage) +: myImageFile(theImage) {} + +StImageFileCounter::~StImageFileCounter() {} + +void StImageFileCounter::createReference(StHandle<StBufferCounter>& theOther) const { + StHandle<StImageFileCounter> anImgFileRef = StHandle<StImageFileCounter>::downcast(theOther); + if(anImgFileRef.isNull()) { + anImgFileRef = new StImageFileCounter(); + theOther = anImgFileRef; + } + anImgFileRef->myImageFile = myImageFile; +} + +void StImageFileCounter::releaseReference() { + myImageFile.nullify(); +}
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StImagePlane.cpp
Changed
(renamed from StShared/StImagePlane.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StJpegParser.cpp
Changed
(renamed from StShared/StJpegParser.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StNsImage.ObjC.mm
Added
@@ -0,0 +1,160 @@ +/** + * Copyright © 2026 Kirill Gavrilov <kirill@sview.ru> + * + * This code is licensed under MIT license (see docs/license-mit.txt for details). + */ + +#include <StImage/StNsImage.h> + +#include <StStrings/StLogger.h> +#include <StThreads/StMutex.h> +#include <StFile/StFileNode.h> + +#ifdef __APPLE__ +#define ST_HAVE_NSIMAGE +#include <StCocoa/StCocoaLocalPool.h> +#include <StCocoa/StCocoaString.h> +#endif + +#include <sstream> + +#ifdef ST_HAVE_NSIMAGE + #import <Cocoa/Cocoa.h> + +namespace { + + /** Convert NSBitmapImageRep format to sView pixel format. */ + static StImagePlane::ImgFormat convertFromNSFormat(NSBitmapImageRep* theNsImgRep) { + if (theNsImgRep isPlanar) { + // planar formats are excluded + return StImagePlane::ImgUNKNOWN; + } + + const bool isFloat = (theNsImgRep bitmapFormat & NSBitmapFormatFloatingPointSamples) != 0; + + if (theNsImgRep samplesPerPixel == 1) { + if (theNsImgRep bitsPerPixel == 8) + return StImagePlane::ImgGray; + else if (!isFloat && theNsImgRep bitsPerPixel == 16) + return StImagePlane::ImgGray16; + else if (isFloat && theNsImgRep bitsPerPixel == 16) // from EXR + return StImagePlane::ImgUNKNOWN; // unsupported half-float format + else if (isFloat && theNsImgRep bitsPerPixel == 32) + return StImagePlane::ImgGrayF; + } else if (theNsImgRep samplesPerPixel == 3) { + if (theNsImgRep bitsPerPixel == 24) + return StImagePlane::ImgRGB; + else if (theNsImgRep bitsPerPixel == 32) + return StImagePlane::ImgRGB32; + else if (theNsImgRep bitsPerPixel == 48) + return StImagePlane::ImgRGB48; + else if (isFloat && theNsImgRep bitsPerPixel == 96) + return StImagePlane::ImgRGBF; + else if (isFloat && theNsImgRep bitsPerPixel == 128) + return StImagePlane::ImgRGBAF; // nit: we don't have RGBF format with unused A + } else if (theNsImgRep samplesPerPixel == 4) { + if (theNsImgRep bitsPerPixel == 32) + return StImagePlane::ImgRGBA; + else if (!isFloat && theNsImgRep bitsPerPixel == 64) + return StImagePlane::ImgRGBA64; + else if (isFloat && theNsImgRep bitsPerPixel == 64) // from EXR + return StImagePlane::ImgUNKNOWN; // unsupported half-float format + else if (isFloat && theNsImgRep bitsPerPixel == 128) + return StImagePlane::ImgRGBAF; + } + + return StImagePlane::ImgUNKNOWN; + } + +} + +void StNsImage::close() { + if (myNSBitmap != nullptr) { + myNSBitmap release; + myNSBitmap = nullptr; + } +} + +bool StNsImage::loadExtra(const StString& theFilePath, + ImageType theImageType, + uint8_t* theDataPtr, + int theDataSize, + bool theIsOnlyRGB) { + (void )theIsOnlyRGB; + if (!StNsImage::init()) { + setState("StNsImage library is not initialized"); + return false; + } + + // reset current data + StImage::nullify(); + setState(); + close(); + + StCocoaLocalPool aLocalPool; + + NSImage* anNsImage = nullptr; + NSData* anNsData = nullptr; + if (theDataPtr != nullptr) { + (void )theImageType; + anNsData = NSData alloc initWithBytesNoCopy: theDataPtr + length: theDataSize + freeWhenDone: NO autorelease; + anNsImage = NSImage alloc initWithData: anNsData autorelease; + } else { + StCocoaString aFilePath(theFilePath); + anNsImage = NSImage alloc initWithContentsOfFile: aFilePath.toStringNs() autorelease; + } + + if (anNsImage == nullptr) { + setState("Unable to read StNsImage"); + return false; + } + + NSBitmapImageRep* anNsImgRep = (NSBitmapImageRep*)anNsImage representations objectAtIndex: 0; + if (!anNsImgRep isKindOfClass: NSBitmapImageRep class) { + setState("Unsupported StNsImage representation"); + return false; + } + + const auto formatImgRep = (NSBitmapImageRep* theRep) -> std::string + { + std::stringstream aStr; + aStr << "NSBitmapImageRep" + << " samplesPerPixel: " << theRep samplesPerPixel + << "; bitsPerPixel: " << theRep bitsPerPixel + << "; size: " << theRep pixelsWide << "x" << theRep pixelsHigh + << "; bytesPerRow: " << theRep bytesPerRow + << "; isPlanar: " << theRep isPlanar + << "; bitmapFormat: " << theRep bitmapFormat + << "; colorSpace: " << theRep colorSpace localizedName UTF8String; + return aStr.str(); + }; + + const StImagePlane::ImgFormat anImgFormat = convertFromNSFormat(anNsImgRep); + if (anImgFormat == StImagePlane::ImgUNKNOWN) { + std::string aFormatStr = formatImgRep(anNsImgRep); + setState(StString("Unsupported ") + aFormatStr.c_str()); + return false; + } + + setColorModelPacked(anImgFormat); + if (!changePlane(0).initWrapper(anImgFormat, + anNsImgRep bitmapData, + anNsImgRep pixelsWide, anNsImgRep pixelsHigh, + anNsImgRep bytesPerRow)) { + setState("Unable to wrap NSImage bitmap"); + return false; + } + changePlane(0).setTopDown(true); + + myNSBitmap = anNsImgRep retain; + + // set debug information + StString aDummy, aFileName; + StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); + setState(StString("StNsImage library, loaded image '") + aFileName + "' " + getDescription()); + return true; +} + +#endif
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StNsImage.cpp
Added
@@ -0,0 +1,49 @@ +/** + * Copyright © 2026 Kirill Gavrilov <kirill@sview.ru> + * + * This code is licensed under MIT license (see docs/license-mit.txt for details). + */ + +#include <StImage/StNsImage.h> + +#include <StStrings/StLogger.h> +#include <StThreads/StMutex.h> +#include <StFile/StFileNode.h> + +#ifdef __APPLE__ +#define ST_HAVE_NSIMAGE +#endif + +bool StNsImage::init() { +#ifdef ST_HAVE_NSIMAGE + return true; +#else + return false; +#endif +} + +StNsImage::StNsImage() { + StNsImage::init(); +#ifndef ST_HAVE_NSIMAGE + (void)myNSBitmap; +#endif +} + +StNsImage::~StNsImage() { + close(); +} + +#ifndef ST_HAVE_NSIMAGE +void StNsImage::close() { + // +} + +bool StNsImage::loadExtra(const StString& , ImageType , uint8_t* , int , bool ) { + return false; +} +#endif + +bool StNsImage::save(const StString&, const SaveImageParams& ) { + setState("StNsImage library, save operation is NOT implemented"); + return false; +}
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StStbImage.cpp
Changed
(renamed from StShared/StStbImage.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StImage/StWicImage.cpp
Added
@@ -0,0 +1,269 @@ +/** + * Copyright © 2026 Kirill Gavrilov <kirill@sview.ru> + * + * This code is licensed under MIT license (see docs/license-mit.txt for details). + */ + +#include <StImage/StWicImage.h> + +#include <StStrings/StLogger.h> +#include <StThreads/StMutex.h> +#include <StFile/StFileNode.h> + +#ifdef _WIN32 +#define ST_HAVE_WINCODEC +#endif + +#ifdef ST_HAVE_WINCODEC + #include <wincodec.h> + +namespace { + + /** Return a zero GUID */ + static GUID getNullGuid() { + GUID aGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; + return aGuid; + } + + /** Sentry over IUnknown pointer. */ + template<class T> class Image_ComPtr { + + public: + + /** Empty constructor. */ + Image_ComPtr() : myPtr(nullptr) {} + + /** Destructor. */ + ~Image_ComPtr() { nullify(); } + + /** Return TRUE if pointer is NULL. */ + bool isNull() const { return myPtr == nullptr; } + + /** Release the pointer. */ + void nullify() { + if (myPtr != nullptr) { + myPtr->Release(); + myPtr = nullptr; + } + } + + /** Return pointer for initialization. */ + T*& changePtr() { + if (myPtr != nullptr) { + ST_ERROR_LOG("StWicImage, Pointer cannot be initialized twice!") + } + return myPtr; + } + + /** Return pointer. */ + T* get() { return myPtr; } + + /** Return pointer. */ + T* operator->() { return get(); } + + /** Cast handle to contained type */ + T& operator*() { return *get(); } + + private: + + T* myPtr = nullptr; + }; + + /** Convert WIC GUID to sView pixel format. */ + static StImagePlane::ImgFormat convertFromWicFormat(const WICPixelFormatGUID& theFormat) { + if (theFormat == GUID_WICPixelFormat32bppBGRA) { + return StImagePlane::ImgBGRA; + } else if (theFormat == GUID_WICPixelFormat32bppBGR) { + return StImagePlane::ImgBGR32; + } else if (theFormat == GUID_WICPixelFormat24bppRGB) { + return StImagePlane::ImgRGB; + } else if (theFormat == GUID_WICPixelFormat24bppBGR) { + return StImagePlane::ImgBGR; + } else if (theFormat == GUID_WICPixelFormat8bppGray) { + return StImagePlane::ImgGray; + } else if (theFormat == GUID_WICPixelFormat16bppGray) { + return StImagePlane::ImgGray16; + } else if (theFormat == GUID_WICPixelFormat32bppGrayFloat) { + return StImagePlane::ImgGrayF; + } else if (theFormat == GUID_WICPixelFormat32bppRGB) { + return StImagePlane::ImgRGB32; + } else if (theFormat == GUID_WICPixelFormat32bppRGBA) { + return StImagePlane::ImgRGBA; + } else if (theFormat == GUID_WICPixelFormat48bppRGB) { + return StImagePlane::ImgRGB48; + } else if (theFormat == GUID_WICPixelFormat64bppRGBA) { + return StImagePlane::ImgRGBA64; + } else if (theFormat == GUID_WICPixelFormat96bppRGBFloat) { + return StImagePlane::ImgRGBF; + } else if (theFormat == GUID_WICPixelFormat128bppRGBAFloat) { + return StImagePlane::ImgRGBAF; + } + // planar formats are excluded + return StImagePlane::ImgUNKNOWN; + } + + /** Convert StImagePlane::ImgFormat to WIC GUID. */ + static WICPixelFormatGUID convertToWicFormat(StImagePlane::ImgFormat theFormat) { + switch (theFormat) { + case StImagePlane::ImgUNKNOWN: return getNullGuid(); + case StImagePlane::ImgGray: return GUID_WICPixelFormat8bppGray; + case StImagePlane::ImgGray16: return GUID_WICPixelFormat16bppGray; + case StImagePlane::ImgRGB: return GUID_WICPixelFormat24bppRGB; + case StImagePlane::ImgBGR: return GUID_WICPixelFormat24bppBGR; + case StImagePlane::ImgRGB32: return GUID_WICPixelFormat32bppRGB; + case StImagePlane::ImgBGR32: return GUID_WICPixelFormat32bppBGR; + case StImagePlane::ImgRGB48: return GUID_WICPixelFormat48bppRGB; + case StImagePlane::ImgRGBA: return GUID_WICPixelFormat32bppRGBA; + case StImagePlane::ImgBGRA: return GUID_WICPixelFormat32bppBGRA; + case StImagePlane::ImgRGBA64: return GUID_WICPixelFormat64bppRGBA; + case StImagePlane::ImgGrayF: return GUID_WICPixelFormat32bppGrayFloat; + case StImagePlane::ImgRGBF: return GUID_WICPixelFormat96bppRGBFloat; + case StImagePlane::ImgBGRF: return getNullGuid(); + case StImagePlane::ImgRGBAF: return GUID_WICPixelFormat128bppRGBAFloat; + case StImagePlane::ImgBGRAF: return getNullGuid(); + case StImagePlane::ImgUV: return getNullGuid(); + } + return getNullGuid(); + } + +} + +#endif + +bool StWicImage::init() { +#ifdef ST_HAVE_WINCODEC + return true; +#else + return false; +#endif +} + +StWicImage::StWicImage() { + StWicImage::init(); +} + +StWicImage::~StWicImage() { + close(); +} + +void StWicImage::close() { + // +} + +bool StWicImage::loadExtra(const StString& theFilePath, + ImageType theImageType, + uint8_t* theDataPtr, + int theDataSize, + bool theIsOnlyRGB) { + (void )theIsOnlyRGB; + if (!StWicImage::init()) { + setState("WIC library is not initialized"); + return false; + } + + // reset current data + StImage::nullify(); + setState(); + close(); + +#ifdef ST_HAVE_WINCODEC + Image_ComPtr<IWICImagingFactory> aWicImgFactory; + CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&aWicImgFactory.changePtr())) != S_OK) { + setState("Cannot initialize WIC Imaging Factory"); + return false; + } + + Image_ComPtr<IWICBitmapDecoder> aWicDecoder; + Image_ComPtr<IWICStream> aWicStream; + + if (theDataPtr != nullptr) { + (void )theImageType; + if (aWicImgFactory->CreateStream(&aWicStream.changePtr()) != S_OK + || aWicStream->InitializeFromMemory((BYTE* )theDataPtr, (DWORD )theDataSize) != S_OK) { + setState("Error: cannot initialize WIC Stream"); + return false; + } + if (aWicImgFactory->CreateDecoderFromStream(aWicStream.get(), nullptr, + WICDecodeMetadataCacheOnDemand, + &aWicDecoder.changePtr()) != S_OK) { + setState("Error: cannot create WIC Image Decoder"); + return false; + } + + } else { + StStringUtfWide aFilePathWide = theFilePath.toUtfWide(); + if (aWicImgFactory->CreateDecoderFromFilename(aFilePathWide.toCString(), nullptr, GENERIC_READ, + WICDecodeMetadataCacheOnDemand, + &aWicDecoder.changePtr()) != S_OK) { + setState("Error: cannot create WIC Image Decoder"); + return false; + } + } + + UINT aFrameCount = 0, aFrameSizeX = 0, aFrameSizeY = 0; + WICPixelFormatGUID aWicPixelFormat = getNullGuid(); + Image_ComPtr<IWICBitmapFrameDecode> aWicFrameDecode; + if (aWicDecoder->GetFrameCount(&aFrameCount) != S_OK + || aFrameCount < 1 + || aWicDecoder->GetFrame(0, &aWicFrameDecode.changePtr()) != S_OK + || aWicFrameDecode->GetSize(&aFrameSizeX, &aFrameSizeY) != S_OK + || aWicFrameDecode->GetPixelFormat(&aWicPixelFormat)) { + setState("Cannot get WIC Image Frame"); + return false; + } + + Image_ComPtr<IWICFormatConverter> aWicConvertedFrame; + StImagePlane::ImgFormat anImgFormat = convertFromWicFormat(aWicPixelFormat); + if (anImgFormat == StImagePlane::ImgUNKNOWN) { + anImgFormat = StImagePlane::ImgRGB; + if (aWicImgFactory->CreateFormatConverter(&aWicConvertedFrame.changePtr()) != S_OK + || aWicConvertedFrame->Initialize(aWicFrameDecode.get(), convertToWicFormat(anImgFormat), + WICBitmapDitherTypeNone, nullptr, 0.0f, + WICBitmapPaletteTypeCustom) != S_OK) { + setState("Cannot convert WIC Image Frame to RGB format"); + return false; + } + ST_DEBUG_LOG("WIC image has been converted to RGB format") + aWicFrameDecode.nullify(); + } + + setColorModelPacked(anImgFormat); + if (!changePlane(0).initTrash(anImgFormat, aFrameSizeX, aFrameSizeY)) { + setState("Unable to allocate memory for image data"); + return false; + } + + IWICBitmapSource* aWicSrc = aWicFrameDecode.get(); + if (!aWicConvertedFrame.isNull()) { + aWicSrc = aWicConvertedFrame.get(); + } + + if (aWicSrc->CopyPixels(nullptr, + (UINT)changePlane(0).getSizeRowBytes(), + (UINT)changePlane(0).getSizeBytes(), + changePlane(0).changeData()) != S_OK) { + setState("Cannot copy pixels from WIC Image"); + return false; + } + changePlane(0).setTopDown(true); + + // set debug information + StString aDummy, aFileName; + StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); + setState(StString("WIC library, loaded image '") + aFileName + "' " + getDescription()); + return true; +#else + (void )theFilePath; + (void )theImageType; + (void )theDataPtr; + (void )theDataSize; + return false; +#endif +} + +bool StWicImage::save(const StString&, const SaveImageParams& ) { + setState("WIC library, save operation is NOT implemented"); + return false; +}
View file
_service:obs_scm:sview-26.obscpio/StShared/StImageFile.cpp
Deleted
@@ -1,313 +0,0 @@ -/** - * Copyright © 2010-2022 Kirill Gavrilov <kirill@sview.ru> - * - * This code is licensed under MIT license (see docs/license-mit.txt for details). - */ - -#include <StImage/StImageFile.h> - -#include <StImage/StDevILImage.h> -#include <StImage/StFreeImage.h> -#include <StImage/StStbImage.h> -#include <StAV/StAVImage.h> -#include <StFile/StFileNode.h> -#include <StFile/StMIME.h> -#include <StFile/StRawFile.h> - -#include <StStrings/StLogger.h> - -/** - * DDS Pixel Format structure. - */ -struct StDDSPixelFormat { - uint32_t Size; - uint32_t Flags; - uint32_t FourCC; - uint32_t RGBBitCount; - uint32_t RBitMask; - uint32_t GBitMask; - uint32_t BBitMask; - uint32_t ABitMask; -}; - -/** - * DDS File header structure. - */ -struct StDDSFileHeader { - /** - * Caps2 flag indicating complete (6 faces) cubemap. - */ - enum { DDSCompleteCubemap = 0xFE00 }; - - /** - * Return TRUE if cubmap flag is set. - */ - bool isCompleteCubemap() const { return (Caps2 & DDSCompleteCubemap) != 0; } - - uint32_t Size; - uint32_t Flags; - uint32_t Height; - uint32_t Width; - uint32_t PitchOrLinearSize; - uint32_t Depth; - uint32_t MipMapCount; - uint32_t Reserved111; - StDDSPixelFormat PixelFormatDef; - uint32_t Caps; - uint32_t Caps2; - uint32_t Caps3; - uint32_t Caps4; - uint32_t Reserved2; -}; - -StImageFile::StImageFile() -: mySrcFormat(StFormat_AUTO), - mySrcPanorama(StPanorama_OFF) { - // -} - -StImageFile::~StImageFile() { - // -} - -StImageFile::ImageClass StImageFile::imgLibFromString(const StString& thePreferred) { - StImageFile::ImageClass aPreferred = ST_LIBAV; - if(thePreferred.isEqualsIgnoreCase(stCString("LibAV")) || - thePreferred.isEqualsIgnoreCase(stCString("FFmpeg")) || - thePreferred.isEqualsIgnoreCase(stCString("StAVImage"))) { - aPreferred = ST_LIBAV; - } else if(thePreferred.isEqualsIgnoreCase(stCString("FreeImage")) || - thePreferred.isEqualsIgnoreCase(stCString("StFreeImage"))) { - aPreferred = ST_FREEIMAGE; - } else if(thePreferred.isEqualsIgnoreCase(stCString("DevIL")) || - thePreferred.isEqualsIgnoreCase(stCString("StDevILImage"))) { - aPreferred = ST_DEVIL; - } else if(thePreferred.isEqualsIgnoreCase(stCString("stb"))) { - aPreferred = ST_STB; - } - return aPreferred; -} - -StString StImageFile::imgLibToString(const ImageClass thePreferred) { - switch(thePreferred) { - case ST_FREEIMAGE: return "FreeImage"; - case ST_DEVIL: return "DevIL"; - case ST_STB: return "stb"; - default: - case ST_LIBAV: return "FFmpeg"; - } -} - -StImageFile::ImageType StImageFile::guessImageType(const StString& theFileName, - const StMIME& theMIMEType) { - StString anExt = !theMIMEType.isEmpty() ? theMIMEType.getExtension() : StFileNode::getExtension(theFileName); - if(anExt.isEqualsIgnoreCase(stCString("mpo")) - || theMIMEType.getMIMEType().isEquals(stCString("image/mpo")) - || theMIMEType.getMIMEType().isEquals(stCString("image/x-mpo"))) { - return StImageFile::ST_TYPE_MPO; - } else if(anExt.isEqualsIgnoreCase(stCString("jps")) - || theMIMEType.getMIMEType().isEquals(stCString("image/jps")) - || theMIMEType.getMIMEType().isEquals(stCString("image/x-jps"))) { - return StImageFile::ST_TYPE_JPS; - } else if(anExt.isEqualsIgnoreCase(stCString("pns")) - || theMIMEType.getMIMEType().isEquals(stCString("image/pns")) - || theMIMEType.getMIMEType().isEquals(stCString("image/x-pns"))) { - return StImageFile::ST_TYPE_PNS; - } else if(anExt.isEqualsIgnoreCase(stCString("jpg")) - || anExt.isEqualsIgnoreCase(stCString("jpeg")) - || anExt.isEqualsIgnoreCase(stCString("jpe")) - || theMIMEType.getMIMEType().isEquals(stCString("image/jpg")) - || theMIMEType.getMIMEType().isEquals(stCString("image/jpeg"))) { - return StImageFile::ST_TYPE_JPEG; - } else if(anExt.isEqualsIgnoreCase(stCString("png")) - || theMIMEType.getMIMEType().isEquals(stCString("image/png"))) { - return StImageFile::ST_TYPE_PNG; - } else if(anExt.isEqualsIgnoreCase(stCString("exr"))) { - return StImageFile::ST_TYPE_EXR; - } else if(anExt.isEqualsIgnoreCase(stCString("psd"))) { - return StImageFile::ST_TYPE_PSD; - } else if(anExt.isEqualsIgnoreCase(stCString("ico"))) { - return StImageFile::ST_TYPE_ICO; - } else if(anExt.isEqualsIgnoreCase(stCString("hdr"))) { - return StImageFile::ST_TYPE_HDR; - } else if(anExt.isEqualsIgnoreCase(stCString("webp")) - || theMIMEType.getMIMEType().isEquals(stCString("image/webp"))) { - return StImageFile::ST_TYPE_WEBP; - } else if(anExt.isEqualsIgnoreCase(stCString("webpll")) - || theMIMEType.getMIMEType().isEquals(stCString("image/webpll"))) { - return StImageFile::ST_TYPE_WEBPLL; - } else if(anExt.isEqualsIgnoreCase(stCString("dds")) - || theMIMEType.getMIMEType().isEquals(stCString("image/vnd-ms.dds"))) { - return StImageFile::ST_TYPE_DDS; - } - return StImageFile::ST_TYPE_NONE; -} - -StHandle<StImageFile> StImageFile::create(const StString& thePreferred, - ImageType theImgType) { - return StImageFile::create(imgLibFromString(thePreferred), theImgType); -} - -StHandle<StImageFile> StImageFile::create(StImageFile::ImageClass thePreferred, - ImageType theImgType) { - (void)theImgType; - // open requested library if it exists - switch(thePreferred) { - case ST_FREEIMAGE: { - if(StFreeImage::init()) { - return new StFreeImage(); - } - break; - } - case ST_DEVIL: { - if(StDevILImage::init()) { - return new StDevILImage(); - } - break; - } - case ST_STB: { - if(StStbImage::init()) { - return new StStbImage(); - } - break; - } - default: - case ST_LIBAV: { - if(StAVImage::init()) { - return new StAVImage(); - } - break; - } - } - - // use default library anyway (that currently always linked) - if(StAVImage::init()) { - return new StAVImage(); - } - return StHandle<StImageFile>(); -} - -bool StImageFile::load(const StString& theFilePath, - ImageType theImageType, - uint8_t* theDataPtr, int theDataSize) { - if(theImageType == ST_TYPE_DDS) { - // Most image libraries ignore arrays/cubemaps in DDS file. - // As DDS format is pretty simple - parse it here and load cubemap as vertically stacked image. - StRawFile aRawFile(theFilePath); - if(theDataPtr == NULL) { - if(!aRawFile.readFile()) { - return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); - } - theDataPtr = (uint8_t* )aRawFile.getBuffer(); - theDataSize = (int )aRawFile.getSize(); - } - - if (theDataSize < 128 - || memcmp (&theDataPtr0, "DDS ", 4) != 0) { - return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); - } - - const StDDSFileHeader* aSrcHeader = (const StDDSFileHeader* )&theDataPtr4; - if (aSrcHeader->Size != 124 - || aSrcHeader->Width == 0 - || aSrcHeader->Height == 0 - || aSrcHeader->Width != aSrcHeader->Height - || aSrcHeader->PixelFormatDef.Size != 32 - || (aSrcHeader->Caps2 & StDDSFileHeader::DDSCompleteCubemap) != StDDSFileHeader::DDSCompleteCubemap) { - return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); - } - - const int aHeaderSize = aSrcHeader->Size + 4; - const int aPayLoadSize = theDataSize - aHeaderSize; - if (aPayLoadSize % 6 != 0 - || aPayLoadSize <= 0) { - return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); - } - - const int aTileDataSize = aPayLoadSize / 6; - StArray<uint8_t> aTileBuffer (aTileDataSize + aHeaderSize); - memcpy(&aTileBuffer.changeFirst(), "DDS ", 4); - memcpy(&aTileBuffer.changeValue(4), aSrcHeader, aSrcHeader->Size); - StDDSFileHeader* aHeaderTile = (StDDSFileHeader* )&aTileBuffer.changeValue(4); - aHeaderTile->Caps2 &= ~(StDDSFileHeader::DDSCompleteCubemap); - - StHandle<StImageFile> aTileImage = createEmpty(); - - memcpy(&aTileBuffer.changeValue(aHeaderSize), &theDataPtraHeaderSize, aTileDataSize); - if(!aTileImage->loadExtra(theFilePath, theImageType, &aTileBuffer.changeFirst(), (int )aTileBuffer.size(), false) - || aTileImage->isNull() - || aTileImage->getSizeX() < 1 - || aTileImage->getSizeY() < 1 - || aTileImage->getSizeX() != aTileImage->getSizeY()) { - return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); - } - - close(); - nullify(); - myMetadata = aTileImage->myMetadata; - myStateDescr = aTileImage->myStateDescr; - mySrcFormat = aTileImage->mySrcFormat; - setColorModel(aTileImage->getColorModel()); - setColorScale(aTileImage->getColorScale()); - setPixelRatio(aTileImage->getPixelRatio()); - const bool isTopDownLayout = aTileImage->isTopDown(); - for(size_t aPlaneId = 0; aPlaneId < 4; ++aPlaneId) { - const StImagePlane& aFromPlane = aTileImage->getPlane(aPlaneId); - const size_t aTileIndex = isTopDownLayout ? 0 : 5; - if(!aFromPlane.isNull()) { - if(!changePlane(aPlaneId).initTrash(aFromPlane.getFormat(), aFromPlane.getSizeX(), aFromPlane.getSizeX() * 6)) { - return false; - } - changePlane(aPlaneId).setTopDown(aFromPlane.isTopDown()); - memcpy(changePlane(aPlaneId).changeData() + aFromPlane.getSizeBytes() * aTileIndex, - aFromPlane.getData(), aFromPlane.getSizeBytes()); - } - } - - for(size_t aTileIter = 1; aTileIter < 6; ++aTileIter) { - memcpy(&aTileBuffer.changeValue(aHeaderSize), &theDataPtraTileIter * aTileDataSize + aHeaderSize, aTileDataSize); - aTileImage = createEmpty(); - if(!aTileImage->loadExtra(theFilePath, theImageType, &aTileBuffer.changeFirst(), (int )aTileBuffer.size(), false) - || aTileImage->isNull() - || aTileImage->getSizeX() != getSizeX() - || aTileImage->getSizeY() != getSizeX() // square - || aTileImage->getColorModel() != getColorModel() - || aTileImage->getPlane().getFormat() != getPlane().getFormat()) { - ST_ERROR_LOG("Internal error: DDS file is decoded into inconsistent tiles"); - return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); - } - - const size_t aTileIndex = isTopDownLayout ? aTileIter : (5 - aTileIter); - for(size_t aPlaneId = 0; aPlaneId < 4; ++aPlaneId) { - const StImagePlane& aFromPlane = aTileImage->getPlane(aPlaneId); - if(!aFromPlane.isNull()) { - memcpy(changePlane(aPlaneId).changeData() + aFromPlane.getSizeBytes() * aTileIndex, - aFromPlane.getData(), aFromPlane.getSizeBytes()); - } - } - } - mySrcPanorama = StPanorama_Cubemap1_6; - return true; - } - return loadExtra(theFilePath, theImageType, theDataPtr, theDataSize, false); -} - -StImageFileCounter::StImageFileCounter() {} - -StImageFileCounter::StImageFileCounter(const StHandle<StImage>& theImage) -: myImageFile(theImage) {} - -StImageFileCounter::~StImageFileCounter() {} - -void StImageFileCounter::createReference(StHandle<StBufferCounter>& theOther) const { - StHandle<StImageFileCounter> anImgFileRef = StHandle<StImageFileCounter>::downcast(theOther); - if(anImgFileRef.isNull()) { - anImgFileRef = new StImageFileCounter(); - theOther = anImgFileRef; - } - anImgFileRef->myImageFile = myImageFile; -} - -void StImageFileCounter::releaseReference() { - myImageFile.nullify(); -}
View file
_service:obs_scm:sview-26.obscpio/StShared/StMonitor.cpp
Changed
@@ -6,12 +6,9 @@ #include <StCore/StMonitor.h> -StMonitor::StMonitor() -: mySysId(0), - myFreq(0), - myFreqMax(0), - myScale(1.0f), - myOrient(Orientation_Landscape) { +#include <sstream> + +StMonitor::StMonitor() { // } @@ -25,7 +22,8 @@ myFreq(theCopy.myFreq), myFreqMax(theCopy.myFreqMax), myScale(theCopy.myScale), - myOrient(theCopy.myOrient) { + myOrient(theCopy.myOrient), + myIsWideGamut(theCopy.myIsWideGamut) { // } @@ -40,6 +38,7 @@ myFreqMax = theCopy.myFreqMax; myScale = theCopy.myScale; myOrient = theCopy.myOrient; + myIsWideGamut = theCopy.myIsWideGamut; return *this; } @@ -48,11 +47,35 @@ } StString StMonitor::toString() const { - StString aStereoType = myEdid.isValid() ? (StString(", stereo type: ") + myEdid.getStereoString()) : StString(); - return StString() - + "Monitor #" + mySysId + ", PnP ID: " + myPnpId + " (" + myName + ")" - + (myOrient == Orientation_Portrait ? ", portrait" : "") + aStereoType + '\n' - + "Connected to " + myGpuName + '\n' - + "freq= " + myFreq + "Hz / freqMax= " + myFreqMax + "Hz / scale= " + myScale + "\n" - + myRect.toString(); + std::stringstream aStr; + aStr << "Monitor #" << mySysId; + + if (!myPnpId.isEmpty()) + aStr << ", PnP ID: " << myPnpId; + + aStr << ", scale: " << myScale; + + if (myEdid.isValid()) + aStr << ", stereo type: " << myEdid.getStereoString(); + + if (myIsWideGamut) + aStr << ", wide gamut"; + + if (myFreq > 0) + aStr << " | freq: " << myFreq << "Hz"; + + if (myFreqMax > 0) + aStr << " (max: " << myFreqMax << "Hz)"; + + if (!myName.isEmpty()) + aStr << ", name: '" << myName << "'"; + + if (myOrient == Orientation_Portrait) + aStr << ", portrait"; + + if (!myGpuName.isEmpty()) + aStr << "\nConnected to " << myGpuName; + + aStr << "\n" << myRect.toString(); + return aStr.str().c_str(); }
View file
_service:obs_scm:sview-26.obscpio/StShared/StPListImpl.mm
Deleted
@@ -1,111 +0,0 @@ -/** - * Copyright © 2011-2015 Kirill Gavrilov - * - * This code is licensed under MIT license (see docs/license-mit.txt for details). - */ - -#if (defined(__APPLE__)) - -#include <StSettings/StSettings.h> - -#include <StStrings/StLogger.h> -#include <StThreads/StProcess.h> - -#include <StCocoa/StCocoaLocalPool.h> -#include <StCocoa/StCocoaString.h> - -#include <sys/stat.h> // mkdir under Linux -#include <sys/types.h> // mkdir under Linux - -#import <Cocoa/Cocoa.h> - -bool StSettings::load() { - StCocoaLocalPool aLocalPool; - StCocoaString aPath(myFilePath); - myDict = NSMutableDictionary dictionaryWithContentsOfFile: aPath.toStringNs(); - if(myDict == nil) { - ST_DEBUG_LOG("StConfig, failed to parse " + myFilePath); - myDict = NSMutableDictionary alloc init; - return false; - } else { - myDict retain; - } - return true; -} - -bool StSettings::flush() { - if(!myToFlush) { - return true; - } - - StCocoaLocalPool aLocalPool; - StCocoaString aPath(myFilePath); - if(myDict writeToFile: aPath.toStringNs() atomically: NO == NO) { - ST_DEBUG_LOG("StConfig, failed write to " + myFilePath); - return false; - } - - myToFlush = false; - return true; -} - -StSettings::StSettings(const StHandle<StResourceManager>& theResMgr, - const StString& theSettingsSet) -: myDict(NULL), - myToFlush(false) { - myFilePath = theResMgr->getSettingsFolder() + theSettingsSet + ".plist"; - load(); -} - -StSettings::~StSettings() { - flush(); - myDict release; -} - -bool StSettings::loadInt32(const StString& theParamPath, - int32_t& theValue) { - StCocoaString aPath(theParamPath); - NSObject* anObj = myDict objectForKey: aPath.toStringNs(); - if(anObj == nil || anObj isKindOfClass: NSNumber class == NO) { - ST_DEBUG_LOG("StConfig, parameter \"" + theParamPath + "\" not found"); - return false; - } - NSNumber* aValue = (NSNumber* )anObj; - theValue = aValue intValue; - return true; -} - -bool StSettings::saveInt32(const StString& theParamPath, - const int32_t& theValue) { - StCocoaString aPath(theParamPath); - NSNumber* aNumber = NSNumber alloc initWithInt: theValue; - myDict setObject: aNumber forKey: aPath.toStringNs(); - aNumber release; - myToFlush = true; - return true; -} - -bool StSettings::loadString(const StString& theParamPath, - StString& theValue) { - StCocoaLocalPool aLocalPool; - StCocoaString aPath(theParamPath); - NSObject* anObj = myDict objectForKey: aPath.toStringNs(); - if(anObj == nil || anObj isKindOfClass: NSString class == NO) { - ST_DEBUG_LOG("StConfig, parameter \"" + theParamPath + "\" not found"); - return false; - } - NSString* aValue = (NSString* )anObj; - theValue = aValue UTF8String; - return true; -} - -bool StSettings::saveString(const StString& theParamPath, - const StString& theValue) { - StCocoaString aPath(theParamPath); - StCocoaString aValue(theValue); - myDict setObject: aValue.toStringNs() forKey: aPath.toStringNs(); - myToFlush = true; - return true; -} - -#endif // __APPLE__
View file
_service:obs_scm:sview-26.obscpio/StShared/StProcess.ObjC.mm
Changed
(renamed from StShared/StSocket.ObjC.mm)
View file
_service:obs_scm:sview-26.obscpio/StShared/StSettings
Added
+(directory)
View file
_service:obs_scm:sview-26.obscpio/StShared/StSettings/StConfigImpl.cpp
Changed
(renamed from StShared/StConfigImpl.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StSettings/StPListImpl.mm
Added
@@ -0,0 +1,111 @@ +/** + * Copyright © 2011-2015 Kirill Gavrilov + * + * This code is licensed under MIT license (see docs/license-mit.txt for details). + */ + +#if (defined(__APPLE__)) + +#include <StSettings/StSettings.h> + +#include <StStrings/StLogger.h> +#include <StThreads/StProcess.h> + +#include <StCocoa/StCocoaLocalPool.h> +#include <StCocoa/StCocoaString.h> + +#include <sys/stat.h> // mkdir under Linux +#include <sys/types.h> // mkdir under Linux + +#import <Cocoa/Cocoa.h> + +bool StSettings::load() { + StCocoaLocalPool aLocalPool; + StCocoaString aPath(myFilePath); + myDict = NSMutableDictionary dictionaryWithContentsOfFile: aPath.toStringNs(); + if(myDict == nil) { + ST_DEBUG_LOG("StConfig, failed to parse " + myFilePath); + myDict = NSMutableDictionary alloc init; + return false; + } else { + myDict retain; + } + return true; +} + +bool StSettings::flush() { + if(!myToFlush) { + return true; + } + + StCocoaLocalPool aLocalPool; + StCocoaString aPath(myFilePath); + if(myDict writeToFile: aPath.toStringNs() atomically: NO == NO) { + ST_DEBUG_LOG("StConfig, failed write to " + myFilePath); + return false; + } + + myToFlush = false; + return true; +} + +StSettings::StSettings(const StHandle<StResourceManager>& theResMgr, + const StString& theSettingsSet) +: myDict(NULL), + myToFlush(false) { + myFilePath = theResMgr->getSettingsFolder() + theSettingsSet + ".plist"; + load(); +} + +StSettings::~StSettings() { + flush(); + myDict release; +} + +bool StSettings::loadInt32(const StString& theParamPath, + int32_t& theValue) { + StCocoaString aPath(theParamPath); + NSObject* anObj = myDict objectForKey: aPath.toStringNs(); + if(anObj == nil || anObj isKindOfClass: NSNumber class == NO) { + ST_DEBUG_LOG("StConfig, parameter \"" + theParamPath + "\" not found in '" + myFilePath + "'"); + return false; + } + NSNumber* aValue = (NSNumber* )anObj; + theValue = aValue intValue; + return true; +} + +bool StSettings::saveInt32(const StString& theParamPath, + const int32_t& theValue) { + StCocoaString aPath(theParamPath); + NSNumber* aNumber = NSNumber alloc initWithInt: theValue; + myDict setObject: aNumber forKey: aPath.toStringNs(); + aNumber release; + myToFlush = true; + return true; +} + +bool StSettings::loadString(const StString& theParamPath, + StString& theValue) { + StCocoaLocalPool aLocalPool; + StCocoaString aPath(theParamPath); + NSObject* anObj = myDict objectForKey: aPath.toStringNs(); + if(anObj == nil || anObj isKindOfClass: NSString class == NO) { + ST_DEBUG_LOG("StConfig, parameter \"" + theParamPath + "\" not found in '" + myFilePath + "'"); + return false; + } + NSString* aValue = (NSString* )anObj; + theValue = aValue UTF8String; + return true; +} + +bool StSettings::saveString(const StString& theParamPath, + const StString& theValue) { + StCocoaString aPath(theParamPath); + StCocoaString aValue(theValue); + myDict setObject: aValue.toStringNs() forKey: aPath.toStringNs(); + myToFlush = true; + return true; +} + +#endif // __APPLE__
View file
_service:obs_scm:sview-26.obscpio/StShared/StSettings/StRegisterImpl.cpp
Changed
(renamed from StShared/StRegisterImpl.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StSettings/StSettings.cpp
Changed
(renamed from StShared/StSettings.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StSettings/StTranslations.cpp
Changed
(renamed from StShared/StTranslations.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StStrings
Added
+(directory)
View file
_service:obs_scm:sview-26.obscpio/StShared/StStrings/StDictionary.cpp
Changed
(renamed from StShared/StDictionary.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StStrings/StLangMap.cpp
Changed
(renamed from StShared/StLangMap.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StStrings/StLogger.ObjC.mm
Changed
(renamed from StShared/StLogger.ObjC.mm)
View file
_service:obs_scm:sview-26.obscpio/StShared/StStrings/StLogger.cpp
Changed
(renamed from StShared/StLogger.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StStrings/StStringUnicode.ObjC.mm
Changed
(renamed from StShared/StStringUnicode.ObjC.mm)
View file
_service:obs_scm:sview-26.obscpio/StShared/StStrings/stConsole.cpp
Changed
(renamed from StShared/stConsole.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StStrings/stUtfTools.cpp
Changed
(renamed from StShared/stUtfTools.cpp)
View file
_service:obs_scm:sview-26.obscpio/StShared/StThread.cpp
Changed
@@ -46,6 +46,42 @@ #ifdef _WIN32 myThread = _beginthreadex(NULL, 0, theThreadFunc, theThreadParam, 0, &myThreadId); #else + if(theThreadName != nullptr && *theThreadName != '\0') { +#if defined(__APPLE__) + // the macOS allows to set name only to the current thread + class NamedThreadProxy { + + public: + + NamedThreadProxy(threadFunction_t theFunc, + void* theParam, + const char* theName) + : myFunc(theFunc), myParam(theParam), myName(theName) {} + + static void* create(void* theSelf) { + const NamedThreadProxy* aProxy = (NamedThreadProxy*)theSelf; + pthread_setname_np(aProxy->myName); + void* aRes = aProxy->myFunc(aProxy->myParam); + delete aProxy; + return aRes; + } + + private: + + threadFunction_t myFunc = nullptr; + void* myParam = nullptr; + const char* myName = nullptr; + }; + + NamedThreadProxy* aProxy = new NamedThreadProxy(theThreadFunc, theThreadParam, theThreadName); + + myHasHandle = (pthread_create(&myThread, (pthread_attr_t* )nullptr, &NamedThreadProxy::create, aProxy) == 0); + if (!myHasHandle) { + delete aProxy; + } + return; +#endif + } myHasHandle = (pthread_create(&myThread, (pthread_attr_t* )NULL, theThreadFunc, theThreadParam) == 0); #endif setName(theThreadName);
View file
_service:obs_scm:sview-26.obscpio/adm/cmake/FindFFmpeg.cmake
Changed
@@ -72,7 +72,7 @@ set_property (TARGET ${aLibIter} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (${aLibIter} PROPERTIES IMPORTED_IMPLIB "${FFMPEG_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${FFMPEG_IMPLIB_SUFFIX}") - set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${FFMPEG_INCLUDE_DIR}) + set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFMPEG_INCLUDE_DIR}") if (FFMPEG_SHAREDLIB_FOUND) if (WIN32) set_target_properties (${aLibIter} PROPERTIES IMPORTED_LOCATION "${FFMPEG_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${CMAKE_SHARED_LIBRARY_SUFFIX}") @@ -99,7 +99,7 @@ add_library (${aLibIter} SHARED IMPORTED) set_property (TARGET ${aLibIter} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (${aLibIter} PROPERTIES IMPORTED_IMPLIB "${FFMPEG_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${FFMPEG_IMPLIB_SUFFIX}") - set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${FFMPEG_INCLUDE_DIR}) + set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FFMPEG_INCLUDE_DIR}") set_target_properties (${aLibIter} PROPERTIES IMPORTED_LOCATION "${FFMPEG_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${CMAKE_SHARED_LIBRARY_SUFFIX}") endforeach() endif()
View file
_service:obs_scm:sview-26.obscpio/adm/cmake/FindFreeImage.cmake
Changed
@@ -60,7 +60,7 @@ set_property (TARGET freeimage APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (freeimage PROPERTIES IMPORTED_IMPLIB "${FREEIMAGE_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${FREEIMAGE_TKNAME}${FREEIMAGE_IMPLIB_SUFFIX}") - set_target_properties (freeimage PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${FREEIMAGE_INCLUDE_DIR}) + set_target_properties (freeimage PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FREEIMAGE_INCLUDE_DIR}") if (FREEIMAGE_SHAREDLIB_FOUND) if (WIN32) set_target_properties (freeimage PROPERTIES IMPORTED_LOCATION "${FREEIMAGE_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${FREEIMAGE_TKNAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
View file
_service:obs_scm:sview-26.obscpio/adm/cmake/FindFreetype.cmake
Changed
@@ -30,7 +30,7 @@ set (FREETYPE_INCLUDE_DIR_FOUND ON) elseif (EXISTS "${FREETYPE_INCLUDE_DIR}/freetype2/ft2build.h") set (FREETYPE_INCLUDE_DIR_FOUND ON) - set (FREETYPE_INCLUDE_DIR "${FREETYPE_INCLUDE_DIR}/freetype2") + set (FREETYPE_INCLUDE_DIR "${FREETYPE_INCLUDE_DIR}/freetype2") endif() if (ANDROID AND EXISTS "${FREETYPE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/libfreetype.so") @@ -69,7 +69,7 @@ set_property (TARGET freetype APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (freetype PROPERTIES IMPORTED_IMPLIB "${FREETYPE_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}freetype${FREETYPE_IMPLIB_SUFFIX}") - set_target_properties (freetype PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${FREETYPE_INCLUDE_DIR}) + set_target_properties (freetype PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FREETYPE_INCLUDE_DIR}") if (FREETYPE_SHAREDLIB_FOUND) if (WIN32) set_target_properties (freetype PROPERTIES IMPORTED_LOCATION "${FREETYPE_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}freetype${CMAKE_SHARED_LIBRARY_SUFFIX}") @@ -88,13 +88,13 @@ endif() if (FREETYPE_FOUND) - set (FREETYPE_INCLUDE_DIR "${FREETYPE_INCLUDE_DIRS}") + set (FREETYPE_INCLUDE_DIR "${FREETYPE_INCLUDE_DIRS}") get_filename_component (FREETYPE_LIBRARY_DIR "${FREETYPE_LIBRARIES}" DIRECTORY) add_library (freetype SHARED IMPORTED) set_property (TARGET freetype APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (freetype PROPERTIES IMPORTED_IMPLIB "${FREETYPE_LIBRARIES}") - set_target_properties (freetype PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${FREETYPE_INCLUDE_DIR}) + set_target_properties (freetype PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FREETYPE_INCLUDE_DIR}") set_target_properties (freetype PROPERTIES IMPORTED_LOCATION "${FREETYPE_LIBRARIES}") endif() endif()
View file
_service:obs_scm:sview-26.obscpio/adm/cmake/FindLibconfigCpp.cmake
Changed
@@ -65,7 +65,7 @@ set_property (TARGET libconfig++ APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (libconfig++ PROPERTIES IMPORTED_IMPLIB "${LIBCONFIGCPP_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${LIBCONFIGCPP_TKNAME}${LIBCONFIGCPP_IMPLIB_SUFFIX}") - set_target_properties (libconfig++ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${LIBCONFIGCPP_INCLUDE_DIR}) + set_target_properties (libconfig++ PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBCONFIGCPP_INCLUDE_DIR}") if (LIBCONFIGCPP_SHAREDLIB_FOUND) if (WIN32) set_target_properties (libconfig++ PROPERTIES IMPORTED_LOCATION "${LIBCONFIGCPP_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${LIBCONFIGCPP_TKNAME}${CMAKE_SHARED_LIBRARY_SUFFIX}")
View file
_service:obs_scm:sview-26.obscpio/adm/cmake/FindOpenAL.cmake
Changed
@@ -70,7 +70,7 @@ set_property (TARGET openal APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (openal PROPERTIES IMPORTED_IMPLIB "${OPENAL_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${OPENAL_TKNAME}${OPENAL_IMPLIB_SUFFIX}") - set_target_properties (openal PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${OPENAL_INCLUDE_DIR}) + set_target_properties (openal PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OPENAL_INCLUDE_DIR}") if (OPENAL_SHAREDLIB_FOUND) if (WIN32) set_target_properties (openal PROPERTIES IMPORTED_LOCATION "${OPENAL_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${OPENAL_TKNAME}${CMAKE_SHARED_LIBRARY_SUFFIX}") @@ -94,7 +94,7 @@ add_library (openal SHARED IMPORTED) set_property (TARGET openal APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (openal PROPERTIES IMPORTED_IMPLIB "${OPENAL_LIBRARY}") - set_target_properties (openal PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${OPENAL_INCLUDE_DIR}) + set_target_properties (openal PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OPENAL_INCLUDE_DIR}") set_target_properties (openal PROPERTIES IMPORTED_LOCATION "${OPENAL_LIBRARY}") endif() endif()
View file
_service:obs_scm:sview-26.obscpio/adm/cmake/FindOpenVR.cmake
Changed
@@ -75,7 +75,7 @@ set_property (TARGET ${aLibIter} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (${aLibIter} PROPERTIES IMPORTED_IMPLIB "${OPENVR_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${OPENVR_BITNESS_SUFFIX}${OPENVR_IMPLIB_SUFFIX}") - set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${OPENVR_INCLUDE_DIR}) + set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OPENVR_INCLUDE_DIR}") if (OPENVR_SHAREDLIB_FOUND) if (WIN32) set_target_properties (${aLibIter} PROPERTIES IMPORTED_LOCATION "${OPENVR_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${OPENVR_BITNESS_SUFFIX}${CMAKE_SHARED_LIBRARY_SUFFIX}") @@ -102,7 +102,7 @@ add_library (${aLibIter} SHARED IMPORTED) set_property (TARGET ${aLibIter} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) set_target_properties (${aLibIter} PROPERTIES IMPORTED_IMPLIB "${OPENVR_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${OPENVR_IMPLIB_SUFFIX}") - set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${OPENVR_INCLUDE_DIR}) + set_target_properties (${aLibIter} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OPENVR_INCLUDE_DIR}") set_target_properties (${aLibIter} PROPERTIES IMPORTED_LOCATION "${OPENVR_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${aLibIter}${CMAKE_SHARED_LIBRARY_SUFFIX}") endforeach() endif()
View file
_service:obs_scm:sview-26.obscpio/include/StCocoa/StCocoaCoords.h
Changed
@@ -45,9 +45,7 @@ private: - CGFloat myScreenBottom; - CGFloat myScale; - CGFloat myUnScale; + CGFloat myScreenBottom = 0; };
View file
_service:obs_scm:sview-26.obscpio/include/StCore/StMonitor.h
Changed
@@ -119,6 +119,16 @@ } /** + * Return TRUE if display supports (some) wide gamut output. + */ + ST_LOCAL bool isWideGamut() const { return myIsWideGamut; } + + /** + * Set if display supports (some) wide gamut output. + */ + ST_LOCAL void setWideGamut(bool theFlag) { myIsWideGamut = theFlag; } + + /** * @return current vertical refresh rate */ ST_LOCAL float getFreq() const { return myFreq; } @@ -186,7 +196,7 @@ ST_CPPEXPORT StString toString() const; ST_LOCAL bool operator==(const StMonitor& compare) const { - if(&compare == this) { + if (&compare == this) { return true; } return compare.mySysId == mySysId @@ -221,11 +231,15 @@ StString myGpuName; //!< attached to this GPU StEDIDParser myEdid; //!< EDID data block if available StRectI_t myRect; //!< virtual space (rectangle) - int mySysId; //!< monitor id - float myFreq; //!< frequency in Hertz - float myFreqMax; //!< maximum frequency in Hertz - float myScale; //!< hight pixel density scale factor - Orientation myOrient; //!< monitor orientation + + int mySysId = 0; //!< monitor id + float myFreq = 0; //!< frequency in Hertz + float myFreqMax = 0; //!< maximum frequency in Hertz + float myScale = 1.0f; //!< hight pixel density scale factor + + Orientation myOrient = Orientation_Landscape; //!< monitor orientation + + bool myIsWideGamut = false; //!< wide gamut support };
View file
_service:obs_scm:sview-26.obscpio/include/StFT/StFTFont.h
Changed
@@ -96,8 +96,19 @@ // Halfwidth and Fullwidth Forms || (theUChar >= 0x03000 && theUChar <= 0x0303F) || (theUChar >= 0x0FF00 && theUChar <= 0x0FFEF) - // Katakana (Japanese) is NOT part of CJK, but CJK fonts usually include these symbols - || (theUChar >= 0x030A0 && theUChar <= 0x030FF); + // Hiragana and Katakana (Japanese) are NOT part of CJK, but CJK fonts usually include these symbols + || isHiragana(theUChar) + || isKatakana(theUChar); + } + + /** @return true if specified character is within subset of Hiragana (Japanese). */ + ST_LOCAL static bool isHiragana(const stUtf32_t theUChar) { + return (theUChar >= 0x03040 && theUChar <= 0x0309F); + } + + /** @return true if specified character is within subset of Katakana (Japanese). */ + ST_LOCAL static bool isKatakana(const stUtf32_t theUChar) { + return (theUChar >= 0x030A0 && theUChar <= 0x030FF); } /**
View file
_service:obs_scm:sview-26.obscpio/include/StGL/StParams.h
Changed
@@ -402,7 +402,22 @@ /** * Reset parameters. */ - void reset() { + bool reset() { + if (mySepDxPx == 0 + && mySepDyPx == 0 + && mySepRotDegrees == 0.0f + && myXRotateDegrees == 0.0f + && myYRotateDegrees == 0.0f + && myZRotateDegrees == 0.0f + && PanCenter.x() == 0.0f + && PanCenter.y() == 0.0f + && myPanPitch == 0.0f + && myPanYaw == 0.0f + && ScaleFactor == 1.0f + && !ToSwapLR) { + return false; + } + mySepDxPx = mySepDyPx = 0; mySepRotDegrees = 0.0f; myXRotateDegrees = 0.0f; @@ -414,6 +429,7 @@ myPanYaw = 0.0f; ScaleFactor = 1.0f; ToSwapLR = false; + return true; } public:
View file
_service:obs_scm:sview-26.obscpio/include/StGLWidgets/StGLImageRegion.h
Changed
@@ -201,6 +201,7 @@ public: //! @name Properties struct { + StHandle<StBoolParamNamed> IsFullscreen; //!< fullscreen state StHandle<StEnumParam> DisplayMode; //!< StGLImageRegion::DisplayMode - display mode StHandle<StEnumParam> DisplayRatio; //!< StGLImageRegion::DisplayRatio - display ratio @@ -236,7 +237,7 @@ */ ST_LOCAL void onParamsChanged(); - ST_LOCAL void doParamsReset(const size_t ); + ST_LOCAL void doParamsReset(const size_t ) { resetParams(); } ST_LOCAL void doParamsGamma(const size_t theDir) { if(!params.stereoFile.isNull()) { @@ -333,7 +334,6 @@ private: //! @name private methods - ST_LOCAL StGLVec2 getMouseMoveFlat(const StPointD_t& theCursorZoFrom, const StPointD_t& theCursorZoTo) const; ST_LOCAL StGLVec2 getMouseMoveSphere(const StPointD_t& theCursorZoFrom, @@ -349,6 +349,8 @@ const StPanorama thePano = StPanorama_OFF); ST_LOCAL void stglDrawView(unsigned int theView); + ST_LOCAL bool resetParams(); + private: //! @name private fields StArrayList< StHandle<StAction> >
View file
_service:obs_scm:sview-26.obscpio/include/StImage/StImageFile.h
Changed
@@ -50,6 +50,8 @@ ST_DEVIL, ST_FREEIMAGE, ST_STB, + ST_WIC, // WinCodec (Windows) + ST_NSIMAGE, // NSImage from AppKit (macOS) } ImageClass; /** Structure for passing parameters to image saving. */
View file
_service:obs_scm:sview-26.obscpio/include/StImage/StNsImage.h
Added
@@ -0,0 +1,56 @@ +/** + * Copyright © 2026 Kirill Gavrilov <kirill@sview.ru> + * + * This code is licensed under MIT license (see docs/license-mit.txt for details). + */ + +#ifndef __StNsImage_h_ +#define __StNsImage_h_ + +#include "StImageFile.h" + +// define StHandle template specialization +class StNsImage; +ST_DEFINE_HANDLE(StNsImage, StImageFile); + +#ifdef __OBJC__ +@class NSBitmapImageRep; +#else +struct NSBitmapImageRep; +#endif + +/** + * This class implements image load/save operations using NSImage from AppKit library (macOS). + */ +class StNsImage : public StImageFile { + + public: + + /** + * Should be called at application start. + */ + ST_CPPEXPORT static bool init(); + + public: + + ST_CPPEXPORT StNsImage(); + ST_CPPEXPORT virtual ~StNsImage(); + + ST_LOCAL virtual StHandle<StImageFile> createEmpty() const ST_ATTR_OVERRIDE { return new StNsImage(); } + + ST_CPPEXPORT virtual void close() ST_ATTR_OVERRIDE; + ST_CPPEXPORT virtual bool loadExtra(const StString& theFilePath, + ImageType theImageType, + uint8_t* theDataPtr, + int theDataSize, + bool theIsOnlyRGB) ST_ATTR_OVERRIDE; + ST_CPPEXPORT virtual bool save(const StString& theFilePath, + const SaveImageParams& theParams) ST_ATTR_OVERRIDE; + + private: + + NSBitmapImageRep* myNSBitmap = nullptr; + +}; + +#endif //__StNsImage_h_
View file
_service:obs_scm:sview-26.obscpio/include/StImage/StWicImage.h
Added
@@ -0,0 +1,46 @@ +/** + * Copyright © 2026 Kirill Gavrilov <kirill@sview.ru> + * + * This code is licensed under MIT license (see docs/license-mit.txt for details). + */ + +#ifndef __StWicImage_h_ +#define __StWicImage_h_ + +#include "StImageFile.h" + +// define StHandle template specialization +class StWicImage; +ST_DEFINE_HANDLE(StWicImage, StImageFile); + +/** + * This class implements image load/save operations using WinCodec library (WinAPI). + */ +class StWicImage : public StImageFile { + + public: + + /** + * Should be called at application start. + */ + ST_CPPEXPORT static bool init(); + + public: + + ST_CPPEXPORT StWicImage(); + ST_CPPEXPORT virtual ~StWicImage(); + + ST_LOCAL virtual StHandle<StImageFile> createEmpty() const ST_ATTR_OVERRIDE { return new StWicImage(); } + + ST_CPPEXPORT virtual void close() ST_ATTR_OVERRIDE; + ST_CPPEXPORT virtual bool loadExtra(const StString& theFilePath, + ImageType theImageType, + uint8_t* theDataPtr, + int theDataSize, + bool theIsOnlyRGB) ST_ATTR_OVERRIDE; + ST_CPPEXPORT virtual bool save(const StString& theFilePath, + const SaveImageParams& theParams) ST_ATTR_OVERRIDE; + +}; + +#endif //__StWicImage_h_
View file
_service:obs_scm:sview-26.obscpio/include/StSettings/StFloat32Param.h
Changed
@@ -238,8 +238,8 @@ /** * Reset value to default. */ - ST_LOCAL void reset() { - setValue(myDefValue); + ST_LOCAL bool reset() { + return setValue(myDefValue); } /**
View file
_service:obs_scm:sview-26.obscpio/include/StThreads/StThread.h
Changed
@@ -69,14 +69,14 @@ ST_LOCAL static const char* getArchString() { #if defined(__aarch64__) && defined(__LP64__) return "AArch64 64-bit"; - #elif defined(__arm__) || defined(__arm64__) + #elif defined(__arm__) || defined(__arm64__) || defined(_M_ARM64) #if defined(__ARM_ARCH_7A__) return "ARMv7-A 32-bit"; #elif defined(__ARM_ARCH_7R__) return "ARMv7-R 32-bit"; #elif defined(__ARM_ARCH_7M__) return "ARMv7-M 32-bit"; - #elif defined(__LP64__) + #elif defined(__LP64__) || defined(_M_ARM64) return "ARM 64-bit"; #else return "ARM 32-bit";
View file
_service:obs_scm:sview-26.obscpio/include/StVersion.h
Changed
@@ -45,7 +45,7 @@ // should be redefined in stconfig.conf #ifndef SVIEW_SDK_VERSION //#define SVIEW_SDK_VERSION 10, 1, 0, 0 - #define SVIEW_SDK_VERSION 26, 2, ST_RELEASE, 7 + #define SVIEW_SDK_VERSION 26, 7, ST_RELEASE, 13 #endif #ifndef SVIEW_SDK_VER_STRING @@ -222,9 +222,9 @@ * Return string representation of the version. */ StString toString() const { - const int aYear = 2026; // __YEAR__; - const int aMonth = 2; //(__MONTH__) + 1; - const int aDay = 7; // __DAY__; + const int aYear = 2026; //__YEAR__; + const int aMonth = 7; //(__MONTH__) + 1; + const int aDay = 13; //__DAY__; StString aState; switch(myVer.rStatus) {
View file
_service:obs_scm:sview-26.obscpio/sview/CMakeLists.txt
Changed
@@ -163,8 +163,13 @@ if (APPLE) add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD COMMAND cp -R -f "${FREETYPE_LIBRARY_DIR}/libfreetype*.dylib" "$<TARGET_FILE_DIR:${PROJECT_NAME}>/../Frameworks") - add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD - COMMAND cp -R -f "${OPENAL_LIBRARY_DIR}/libopenal*.dylib" "$<TARGET_FILE_DIR:${PROJECT_NAME}>/../Frameworks") + + if (OPENAL_LIBRARY_DIR MATCHES ".*/System/Library/Frameworks") + message (STATUS "Hint: consider using OpenAL Soft instead of system-provided OpenAL.framework for better experience") + else() + add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD + COMMAND cp -R -f "${OPENAL_LIBRARY_DIR}/libopenal*.dylib" "$<TARGET_FILE_DIR:${PROJECT_NAME}>/../Frameworks") + endif() foreach (aLibIter ${FFMPEG_TKLIST}) add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
View file
_service:obs_scm:sview-26.obscpio/sview/main.ObjC.mm
Changed
@@ -9,6 +9,7 @@ #include "StAppResponder.h" #include "StMultiApp.h" +#include <StCore/StSearchMonitors.h> #include <StCocoa/StCocoaLocalPool.h> #include <StVersion.h> @@ -67,7 +68,10 @@ } myStApp.nullify(); myTimer = NULL; - myIsThreaded = true; + + // latest macOS versions cause sView crashes with background OpenGL thread + myIsThreaded = false; + myIsStarted = false; return self; } @@ -214,7 +218,7 @@ if(myIsThreaded) { // start StApplication instance in dedicated thread ST_DEBUG_LOG("StAppResponder, application started in dedicated thread"); - myThread = new StThread(anAppThreadFunc, self); + myThread = new StThread(anAppThreadFunc, self, "StApplication"); } else { // process StApplication rendering iterations by timer ST_DEBUG_LOG("StAppResponder, application started in main thread!"); @@ -240,6 +244,15 @@ myStApp.nullify(); return false; } + + if(!myStApp->getMainWindow().isNull()) { + // just debug output Monitors' configuration - for consistency with StApplication::exec() + const StSearchMonitors& aMonitors = myStApp->getMainWindow()->getMonitors(); + for(size_t aMonIter = 0; aMonIter < aMonitors.size(); ++aMonIter) { + ST_DEBUG_LOG(aMonitorsaMonIter.toString()); + } + } + return true; } @@ -342,6 +355,7 @@ #endif StProcess::setEnv(ST_ENV_NAME_STCORE_PATH, StProcess::getProcessFolder()); #endif + StThread::setCurrentThreadName("main"); // autorelease pool is required for Cocoa StCocoaLocalPool aPool;
View file
_service:obs_scm:sview.obsinfo
Changed
@@ -1,4 +1,4 @@ name: sview version: 26 -mtime: 1770480909 -commit: b6aea11ce34d183c00177a377a7a66f13e1f535a +mtime: 1783959192 +commit: 8671c35287aa8b260c788b6ccbd152ec826bcb2e
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.