1
0
Fork 0

Compare commits

...

81 Commits

Author SHA1 Message Date
wangqr 6b41659178 Upgrade LuaJIT to 2.1.0-beta3 2019-09-14 19:08:13 -04:00
wangqr 186c98308e Use gettext for desktop file instead of intltool 2019-09-13 17:59:38 -04:00
wangqr 7c500a096a Search user fonts in GDI font lister
Windows now allow user install fonts without admin. List HKCU for those fonts.
https://blogs.windows.com/windowsexperience/2018/06/27/announcing-windows-10-insider-preview-build-17704/
2019-09-13 15:49:15 -04:00
wangqr bd4c7789cf Add openal and CMake test to travis 2019-09-12 02:42:11 -04:00
wangqr 3eff75d56e In tagless_find_helper only tag before start should be ignored
The search result is irrelevant to which tag we should ignore

Fix wangqr/Aegisub#17
2019-09-11 11:29:20 -04:00
wangqr da699f124e Fix wrong memset usage 2019-09-10 02:15:48 -04:00
wangqr 1204a3be85 Cleanup CMake 2019-09-10 01:37:48 -04:00
wangqr 9e6b7e94c0 Fix crash in cache invalidation
The original version uses a reverse iterator, whose .base() is invalid after KillMacroBlock() erases it.

Fix TypesettingTools/Aegisub#33
Fix Aegisub/Aegisub#142
2019-09-08 13:01:55 -04:00
davste0816 ad02d39f44 Fix Move Down button in Export dialog 2019-09-08 11:37:52 -04:00
davste0816 d914ad72b5 Add .webm to extension list, add .eac3 as an audio format
Co-Authored-By: FichteFoll <fichtefoll2@googlemail.com>
2019-09-08 11:37:52 -04:00
davste0816 055aa379e5 Recognize .opus as an audio format, .h264 .hevc as video formats 2019-09-08 11:37:45 -04:00
wangqr 97792e15a8 Add WITH_* switchs to CMake to optional features 2019-09-08 07:12:19 -04:00
wangqr 4a874de442 Fix missing autopoint 2019-09-08 05:53:48 -04:00
scx 5d14137710 make_pot.sh: Check presence of xmlstarlet and jq 2019-09-08 04:35:05 -04:00
scx d252dcf32d Integrate AppData file with build system 2019-09-08 04:35:05 -04:00
scx 4f351b8b4a Add AppData file template 2019-09-08 04:35:05 -04:00
scx c4e0f40370 Fix compiler flags
http://devel.aegisub.org/ticket/1899
http://devel.aegisub.org/ticket/1900
https://github.com/Aegisub/Aegisub/pull/29
2019-09-08 02:25:56 -04:00
scx 05c0ba0e46 Add missing AM_GNU_GETTEXT_VERSION macro
Bug: http://devel.aegisub.org/ticket/1914
2019-09-08 02:22:51 -04:00
wangqr e4e04c9e87 Stop using deprecated hunspell API 2019-09-08 00:29:41 -04:00
wangqr 81160b2ec0 Remove conflicting glext.h 2019-09-07 22:29:23 -04:00
wangqr bf28e7efc3 Add PulseAudio to cmake 2019-09-07 12:35:27 -04:00
wangqr c2c44f1ad2 Fix build warnings
For pimpl with anonymous namespace, see https://stackoverflow.com/questions/39684438
2019-09-07 01:31:16 -04:00
wangqr 5dd201bc2d Update README.md and prepare for release 2019-09-05 22:16:58 -04:00
wangqr 3663d118b6 Separate desktop template for CMake
So it does not affect the translation
2019-09-04 22:46:29 -04:00
wangqr 60a722db31 Don't internally reset the selection after collected fonts
This creates an inconsistency between UI and internal mode.

Fix wangqr/Aegisub#10
2019-09-03 11:58:20 -04:00
wangqr d65643ddee Remove extra semicolon 2019-09-02 22:23:19 -04:00
wangqr fbca222295 Add back original travis tests 2019-09-02 22:06:41 -04:00
wangqr 3225ae39f4 Fix Makefile build
A missing header (acconf.h) issue was introduced in 34575a9786
In 419386aadd, some new source files have been added but not added to the file list in Makefile
2019-09-02 13:46:50 -04:00
wangqr 888be0607f visualSubToolBar now use same style as other toolbars
Previously visualSubToolBar has boarder while visualToolBar does not. So the width of the toolbar will change when toggling visualSubToolBar.

Now we remove the boarder so they have the same width. A separator is added at the top of visualToolBar instead to provide visual cue.

Fix wangqr/Aegisub#11
2019-09-01 22:55:13 -04:00
scx 4200b85fb4 Fix crashing when picking language
Aegisub crashes immediately after selecting any language
from the end of the list (above the 100th position).
This is because it can support no more than 100 languages.
This patch extends this limit up to 1000 languages (locales).

Fixes Aegisub/Aegisub#131
2019-09-01 19:17:35 -04:00
wangqr 0b8b286767 Fix crash on right click due to no spell checker 2019-09-01 19:15:28 -04:00
wangqr 139132a964 Use AviSynth from system 2019-09-01 19:15:21 -04:00
wangqr 4a3689d6e7 Remove the trailing period in help text of time/align
Fix wangqr/Aegisub#7
2019-08-24 02:10:08 -04:00
wangqr 248e69a9b6 Use absolute distance when scrolling audio box with mouse wheel
Instead of 1/3 screen per tick. So the distance of scroll no longer depends on the width of the audio box. Besides, 1/3 is feels to far for me when the audio box is wide.

See wangqr/Aegisub#5
2019-08-24 01:16:18 -04:00
wangqr 46474e0319 Set the height of sub box to the same as secondary_editor
The secondary_editor is a wxTextCtrl, whose height is calculated from 2 rows of text. Using this height gives better consistency on screens with different DPIs, instead of using hard coded value like 50px
2019-08-24 01:12:16 -04:00
wangqr 50544cf749 Set the height of sub box back to 50px
Revert the change made in ad15c53fb1.
As a temporary solution for wangqr/Aegisub#4.
2019-08-18 22:25:50 -04:00
wangqr e9a68f22b9 Remove the usage of dummy wxTimerEvent 2019-07-24 09:11:17 -04:00
wangqr d6ddea0f65 Detect EBML magic number to skip encoding detection for MKV
MKV loads slow after f733297499
2019-06-16 19:16:31 -04:00
wangqr 2bbed6c5a0 Load audio when video is successfully loaded
Fix bug introduced in 8f40ca44ce
2019-06-06 16:32:26 -04:00
wangqr 592250eeaa Remove call to wxSizer::CalcMin and wxSizer::RecalcSizes
As they are used internally by Layout and should not be called
directly.
2019-06-06 15:24:40 -04:00
wangqr 8f40ca44ce Try auto loading audio from video only when actually loading a video
If the user drop some files into Aegisub, we try to load sub, video,
audio, etc from them. When "Automatically open audio when opening
video" is checked in config, we try to load audio from the path of
the video. This should only be done if the video is newly loaded. So
we should never try to load audio from video if the user is just
opening a subtitle.

See https://github.com/Aegisub/Aegisub/issues/121#issuecomment-498489847
2019-06-06 14:31:07 -04:00
wangqr f776db2d2b Change the default fontsize and the list of resolutions
The default fontsize is changed to 48. While it still looks small
on the default 720p video, it is actually bigger than
    20 / 480 * 720 = 30

Here 720p is the default video resolution after 837d5a41d7. Some
common resolutions are also added to the preset list.

Fix wangqr/Aegisub#3
2019-06-03 22:08:11 -04:00
wangqr f9ffc46bf6 Add linux desktop icon 2019-05-22 20:45:51 -04:00
wangqr 019e68147e Fix FFT first sample location
Fix wangqr/Aegisub#1
2019-05-22 20:10:09 -04:00
wangqr f733297499 Rewrite encoding detection
Now feeds all data to uchardet, when uchardet is available. The file
size limit is removed.

When uchardet is not available, we look for UTF-8 BOM.
This should make loading UTF-8-BOM files faster.
Because Aegisub always save file in UTF-8-BOM, this should also
guarentee Aegisub will load large (>100MB) file saved by itself.

See Aegisub/Aegisub#110
2019-05-18 22:13:26 -04:00
wangqr 4c6d370d51 Add install target 2019-05-18 20:10:18 -04:00
wangqr b7c640d061 Fix High DPI issue on GTK
* Use icon size in the config
2019-05-17 13:58:14 -04:00
wangqr 2c06f03f5b Add AviSynth support 2019-05-16 11:07:57 -04:00
wangqr 1819fc8d8b Fix iconv ConversionFailure on long path 2019-05-16 11:04:53 -04:00
wangqr ba54e8d12f Fix build warnings 2019-05-11 21:36:34 -04:00
Ryan Lucia c76e410d30 Divorce stored TPP lead-in/out values from config
There's no real reason to link these as far as I can tell, and plenty of
valid reasons not to
2019-05-11 20:04:29 -04:00
Ryan Lucia bb2cfb1fcd Properly ignore ASS whitespace characters in character counter 2019-05-11 20:00:49 -04:00
Ryan Lucia 9abcc03202 Add configuration options for colors in visual typesetting tools 2019-05-11 19:43:54 -04:00
Ryan Lucia 837d5a41d7 Update default config to modern standards 2019-05-11 19:38:10 -04:00
Ryan Lucia 875456c803 Use FFMS2 constant in place of magic number 2019-05-10 15:22:26 -04:00
Ryan Lucia 9ddecfdd46 Ignore VS build files
Most files were moved to .vs directory with VS15
2019-05-10 15:17:19 -04:00
Ryan Lucia 70f27eae4b Pass 0 to FFMS_Init
The argument is no longer used, and the docs specify to pass a value of 0 to avoid confusion
2019-05-10 15:12:55 -04:00
Ryan Lucia 8d2ef3fca7 Point users at a functional bug tracker 2019-05-10 15:09:25 -04:00
Ryan Lucia 48869ae0ad Fix line order when splitting after current frame 2019-05-10 15:09:05 -04:00
Ryan Lucia b00285cf71 Use proper event for DoubleUpdater
Previously changes weren't recognized because the event bound was for integers
2019-05-10 15:06:01 -04:00
Ryan Lucia c6c9e05406 Remove dead forums link 2019-05-10 15:05:18 -04:00
Ryan Lucia fc1a78aeca Make translation assistant skipping whitespace an explicit setting 2019-05-10 15:04:48 -04:00
Ryan Lucia 38bb1790ab Remove Force BT.601 option and update color matrix guessing 2019-05-10 15:03:20 -04:00
Ryan Lucia fff08c4650 Add support for setting status bar text from Lua 2019-05-10 14:54:05 -04:00
wangqr 163d57d6a2 Fix LuaJIT segfault 2019-05-09 21:36:11 -04:00
wangqr 6266867586 Fix errors in AlignToVideo
* Call TimeAtFrame with correct parameter
* Fix syntax error
2019-05-09 16:54:20 -04:00
wangqr 4431f678ce Update about dialog 2019-05-09 16:30:38 -04:00
Charlie Jiang 419386aadd Merge remote-tracking branch 'origind-dev/master'
Add align to video function
2019-05-09 16:26:08 -04:00
wangqr c4cce28766 Update README to use CMake 2019-05-08 22:49:53 -04:00
wangqr 1ae2f60b9a Fix CMake build errors 2019-05-08 17:09:29 -04:00
wangqr b6eebcd7ef Fix build warnings 2019-05-08 17:09:07 -04:00
wangqr bf55264e6d Fix VS2019 compile issues 2019-05-08 16:34:53 -04:00
wangqr 34575a9786 Migrate to CMake to update packages easier 2019-05-08 16:34:39 -04:00
wangqr 69310d40ae Correctly handle memory free using Lua GC
Instead of manually free. Otherwise return value of `search' may refer to invalid memory.
Fix Aegisub/Aegisub#99
2019-03-15 00:01:29 -04:00
wangqr 657d9d5149 Bump boost version to 1.69.0
Fix Aegisub/Aegisub#93
2019-03-14 23:58:28 -04:00
wangqr 043a45cf91 Add DPI aware to Aegisub manifest 2018-12-08 01:20:08 -05:00
wangqr ad15c53fb1 Add DPI awareness
* Removed most hard coded wxSize
* Sub edit box now have DPI aware icons
2018-12-08 01:20:08 -05:00
wangqr 841a35a6fd Fix overflow bound 2018-12-08 01:20:08 -05:00
wangqr ee7dc6af4e Fix millisecond to centisecond convertion
Fix Aegisub/Aegisub#94
2018-12-08 01:20:08 -05:00
wangqr 77da2436c5 Change some text box size to make it looks better on HiDPI 2018-12-08 01:20:08 -05:00
wangqr 7be2325629 Fix travis-ci build script 2018-12-08 00:48:00 -05:00
367 changed files with 46641 additions and 23581 deletions

3
.gitignore vendored
View File

@ -5,6 +5,7 @@
*.bz2
*.cache
*.dep
*.db
*.dll
*.dmg
*.exe
@ -14,6 +15,7 @@
*.ilk
*.log
*.manifest
!src/dpi_aware.manifest
*.mkv
*.mo
*.ncb
@ -86,3 +88,4 @@ vendor/luajit/src/lj_vm.s
vendor/luajit/src/luajit
.nuget
.vs

View File

@ -1,5 +1,5 @@
sudo: required
dist: trusty
dist: bionic
language: cpp
git:
@ -8,58 +8,68 @@ git:
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.kitware.com/ubuntu/ bionic main'
key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc'
packages:
- libasound2-dev
- libfftw3-dev
- libhunspell-dev
- yasm
- libfribidi-dev
- libass-dev
- libicu-dev
- luarocks
- g++-5
- cmake
- build-essential
- libboost-all-dev
- libffms2-dev
- libfontconfig1-dev
- libopenal-dev
- libuchardet-dev
- libwxgtk3.0-dev
- portaudio19-dev
- libpulse-dev
- autopoint
- libgtest-dev
matrix:
include:
- compiler: gcc
env: BOOST_VERSION=55
- compiler: gcc
env: BOOST_VERSION=60
before_install:
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 60 --slave /usr/bin/g++ g++ /usr/bin/g++-5 --slave /usr/bin/gcov gcov /usr/bin/gcov-5
- {}
- env: BUILD_SUIT=autotools
install:
# Can't install these via the apt addon due to the whitelist
- sudo apt-get install -y -qq libffms2-dev libwxgtk3.0-dev libuchardet-dev
- sudo pip install cpp-coveralls
- sudo luarocks install busted > /dev/null
- sudo luarocks install moonscript > /dev/null
- sudo luarocks install uuid > /dev/null
- git submodule --quiet init
- git submodule --quiet update vendor/googletest
- cd vendor
- rm -rf boost
- wget http://sourceforge.net/projects/boost/files/boost/1.${BOOST_VERSION}.0/boost_1_${BOOST_VERSION}_0.tar.bz2/download
- tar xjf download
- mv boost_1_${BOOST_VERSION}_0 boost
- cd boost
- ./bootstrap.sh
- ./b2 -j3 -layout=system threading=multi cxxflags=-std=c++11 link=shared variant=release --without-python --without-iostreams --without-serialization --without-graph --without-log --without-math --without-signals --without-test --without-wave --without-mpi --without-program_options --without-graph_parallel --without-context --without-coroutine --without-random --without-timer --without-date_time
- cd ../..
- sudo luarocks install busted > /dev/null
- sudo luarocks install moonscript > /dev/null
- sudo luarocks install uuid > /dev/null
# Remove the CMake provided by travis
- sudo rm -rf /usr/local/cmake*
- if [ "$BUILD_SUIT" = "autotools" ]; then
sudo pip install -U cpp-coveralls;
git submodule --quiet init;
git submodule --quiet update vendor/googletest;
else
pushd /usr/src/googletest;
sudo cmake .;
sudo make install -j2;
popd;
fi
script:
- export CPATH=$(pwd)/vendor/boost
- export LD_LIBRARY_PATH=$(pwd)/vendor/boost/stage/lib:$LD_LIBRARY_PATH
- export CPPFLAGS="-fprofile-arcs -ftest-coverage"
- export LIBS="-lgcov"
- autoreconf -if
- ./configure BOOST_LDFLAGS="-L$(pwd)/vendor/boost/stage/lib" --enable-debug || cat config.log
- make -j3 all test
- coveralls --exclude vendor --exclude src --exclude build --exclude tools --exclude libaegisub/windows > /dev/null
- if [ "$BUILD_SUIT" = "autotools" ]; then
export CPPFLAGS="-fprofile-arcs -ftest-coverage";
export LIBS="-lgcov";
./autogen.sh;
./configure --enable-debug agi_cv_with_openal=yes || cat config.log;
make -j2;
make test || travis_terminate 1;
coveralls --exclude vendor --exclude src --exclude build --exclude tools --exclude libaegisub/windows > /dev/null;
else
./build/version.sh .;
mkdir build-dir;
cd build-dir;
cmake -DCMAKE_CXX_FLAGS='-Wall -Wextra -Wno-unused-parameter -pedantic' -DCMAKE_C_FLAGS='-Wall' -DWITH_STARTUPLOG=ON -DWITH_TEST=ON ..;
make -j2;
make test || travis_terminate 1;
fi
notifications:
email:

78
CMakeLists.test.txt Normal file
View File

@ -0,0 +1,78 @@
if(UNIX)
add_executable(aegisub-lua EXCLUDE_FROM_ALL
automation/tests/aegisub.cpp
)
target_include_directories(aegisub-lua PRIVATE ${Boost_INCLUDE_DIRS})
target_link_directories(aegisub-lua PRIVATE ${Boost_LIBRARY_DIRS})
target_link_libraries(aegisub-lua libaegisub luabins luajit ${Boost_LIBRARIES} ${ICU_LIBRARIES})
add_custom_target(test-automation
COMMAND sh -c "$(luarocks path); ${PROJECT_BINARY_DIR}/aegisub-lua tests/busted.lua -p moon tests/modules"
VERBATIM
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/automation"
)
add_dependencies(test-automation aegisub-lua)
else()
add_custom_target(test-automation)
endif()
find_package(GTest)
if(GTEST_FOUND)
add_executable(gtest-run EXCLUDE_FROM_ALL
tests/tests/access.cpp
tests/tests/audio.cpp
tests/tests/cajun.cpp
tests/tests/calltip_provider.cpp
tests/tests/character_count.cpp
tests/tests/color.cpp
tests/tests/dialogue_lexer.cpp
tests/tests/format.cpp
tests/tests/fs.cpp
tests/tests/hotkey.cpp
tests/tests/iconv.cpp
tests/tests/ifind.cpp
tests/tests/karaoke_matcher.cpp
tests/tests/keyframe.cpp
tests/tests/line_iterator.cpp
tests/tests/line_wrap.cpp
tests/tests/mru.cpp
tests/tests/option.cpp
tests/tests/path.cpp
tests/tests/signals.cpp
tests/tests/split.cpp
tests/tests/syntax_highlight.cpp
tests/tests/thesaurus.cpp
tests/tests/time.cpp
tests/tests/type_name.cpp
tests/tests/util.cpp
tests/tests/uuencode.cpp
tests/tests/vfr.cpp
tests/tests/word_split.cpp
tests/support/main.cpp
tests/support/util.cpp
)
target_compile_definitions(gtest-run PRIVATE CMAKE_BUILD)
target_include_directories(gtest-run PRIVATE tests/support ${GTEST_INCLUDE_DIRS})
target_link_libraries(gtest-run libaegisub ${Boost_LIBRARIES} ${ICU_LIBRARIES} ${GTEST_LIBRARIES})
if(MSVC)
set_target_properties(gtest-run PROPERTIES COMPILE_FLAGS "/Yu${PROJECT_SOURCE_DIR}/tests/support/tests_pre.h" COMPILE_FLAGS "/FI${PROJECT_SOURCE_DIR}/tests/support/tests_pre.h")
else()
target_compile_options(gtest-run PRIVATE -include "${PROJECT_SOURCE_DIR}/tests/support/tests_pre.h")
endif()
if(WIN32)
add_custom_target(test-aegisub
COMMAND "${PROJECT_SOURCE_DIR}/tests/setup.bat"
COMMAND gtest-run
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/tests"
)
else()
add_custom_target(test-aegisub
COMMAND "${PROJECT_SOURCE_DIR}/tests/setup.sh"
COMMAND gtest-run
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/tests"
)
endif()
else()
add_custom_target(test-aegisub)
endif()
add_custom_target(test DEPENDS test-automation test-aegisub)

809
CMakeLists.txt Normal file
View File

@ -0,0 +1,809 @@
cmake_minimum_required(VERSION 3.14)
cmake_policy(SET CMP0074 NEW)
project(Aegisub)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
include_directories("build")
include_directories("libaegisub/include")
include_directories("vendor/luajit/src")
add_library(libaegisub STATIC
libaegisub/common/parser.cpp
libaegisub/ass/dialogue_parser.cpp
libaegisub/ass/time.cpp
libaegisub/ass/uuencode.cpp
libaegisub/audio/provider.cpp
libaegisub/audio/provider_convert.cpp
libaegisub/audio/provider_dummy.cpp
libaegisub/audio/provider_hd.cpp
libaegisub/audio/provider_lock.cpp
libaegisub/audio/provider_pcm.cpp
libaegisub/audio/provider_ram.cpp
libaegisub/common/cajun/elements.cpp
libaegisub/common/cajun/reader.cpp
libaegisub/common/cajun/writer.cpp
libaegisub/lua/modules/lfs.cpp
libaegisub/lua/modules/re.cpp
libaegisub/lua/modules/unicode.cpp
libaegisub/lua/modules/lpeg.c
libaegisub/lua/modules.cpp
libaegisub/lua/script_reader.cpp
libaegisub/lua/utils.cpp
libaegisub/common/calltip_provider.cpp
libaegisub/common/character_count.cpp
libaegisub/common/charset.cpp
libaegisub/common/charset_6937.cpp
libaegisub/common/charset_conv.cpp
libaegisub/common/color.cpp
libaegisub/common/file_mapping.cpp
libaegisub/common/format.cpp
libaegisub/common/fs.cpp
libaegisub/common/hotkey.cpp
libaegisub/common/io.cpp
libaegisub/common/json.cpp
libaegisub/common/kana_table.cpp
libaegisub/common/karaoke_matcher.cpp
libaegisub/common/keyframe.cpp
libaegisub/common/line_iterator.cpp
libaegisub/common/log.cpp
libaegisub/common/mru.cpp
libaegisub/common/option.cpp
libaegisub/common/option_value.cpp
libaegisub/common/path.cpp
libaegisub/common/thesaurus.cpp
libaegisub/common/util.cpp
libaegisub/common/vfr.cpp
libaegisub/common/ycbcr_conv.cpp
libaegisub/common/dispatch.cpp
)
if(UNIX)
target_sources(libaegisub PRIVATE
libaegisub/unix/access.cpp
libaegisub/unix/fs.cpp
libaegisub/unix/log.cpp
libaegisub/unix/path.cpp
libaegisub/unix/util.cpp
)
set_property(
SOURCE libaegisub/unix/path.cpp
PROPERTY COMPILE_DEFINITIONS
P_DATA="${CMAKE_INSTALL_PREFIX}/share/aegisub/"
)
elseif(WIN32)
target_sources(libaegisub PRIVATE
libaegisub/windows/access.cpp
libaegisub/windows/charset_conv_win.cpp
libaegisub/windows/fs.cpp
libaegisub/windows/lagi_pre.cpp
libaegisub/windows/log_win.cpp
libaegisub/windows/path_win.cpp
libaegisub/windows/util_win.cpp
)
endif()
set_target_properties(libaegisub PROPERTIES PREFIX "")
target_compile_definitions(libaegisub PRIVATE CMAKE_BUILD)
add_library(luabins STATIC
vendor/luabins/src/fwrite.c
vendor/luabins/src/load.c
vendor/luabins/src/luabins.c
vendor/luabins/src/luainternals.c
vendor/luabins/src/save.c
vendor/luabins/src/savebuffer.c
vendor/luabins/src/write.c
)
add_executable(luajit-minilua vendor/luajit/src/host/minilua.c)
if(NOT WIN32)
target_link_libraries(luajit-minilua m)
endif()
if(WIN32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/buildvm_arch.h
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen
COMMAND luajit-minilua ../dynasm/dynasm.lua -LN -D WIN -D JIT -D FFI -D P64 -o gen/buildvm_arch.h vm_x86.dasc
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
else()
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/buildvm_arch.h
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen
COMMAND luajit-minilua ../dynasm/dynasm.lua -LN -D WIN -D JIT -D FFI -o gen/buildvm_arch.h vm_x86.dasc
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
endif()
else()
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/buildvm_arch.h
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen
COMMAND luajit-minilua ../dynasm/dynasm.lua -D P64 -D JIT -D FFI -D FPU -D HFABI -D VER= -o gen/buildvm_arch.h vm_x86.dasc
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
else()
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/buildvm_arch.h
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen
COMMAND luajit-minilua ../dynasm/dynasm.lua -D JIT -D FFI -D FPU -D HFABI -D VER= -o gen/buildvm_arch.h vm_x86.dasc
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
endif()
endif()
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/src/libresrc/default_config.cpp ${PROJECT_SOURCE_DIR}/src/libresrc/default_config.h
DEPENDS ${PROJECT_SOURCE_DIR}/src/libresrc/default_config_platform.json
COMMAND luajit-minilua ../../tools/respack.lua manifest.respack default_config.cpp default_config.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/libresrc
)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/src/libresrc/bitmap.cpp ${PROJECT_SOURCE_DIR}/src/libresrc/bitmap.h
COMMAND luajit-minilua ../../tools/respack.lua manifest.respack ../libresrc/bitmap.cpp ../libresrc/bitmap.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src/bitmaps
)
add_executable(luajit-buildvm
vendor/luajit/src/host/buildvm.c
vendor/luajit/src/host/buildvm_asm.c
vendor/luajit/src/host/buildvm_peobj.c
vendor/luajit/src/host/buildvm_lib.c
vendor/luajit/src/host/buildvm_fold.c
vendor/luajit/src/gen/buildvm_arch.h
)
target_compile_definitions(luajit-buildvm PRIVATE LUAJIT_ENABLE_LUA52COMPAT)
target_include_directories(luajit-buildvm PRIVATE vendor/luajit/src vendor/luajit/src/gen)
if(UNIX)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/lj_vm.s
COMMAND luajit-buildvm -m elfasm -o lj_vm.s
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
elseif(MSVC)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/lj_vm.obj
COMMAND luajit-buildvm -m peobj -o lj_vm.obj
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
endif()
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/lj_ffdef.h
COMMAND luajit-buildvm -m ffdef -o gen/lj_ffdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/lj_bcdef.h
COMMAND luajit-buildvm -m bcdef -o gen/lj_bcdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/lj_folddef.h
COMMAND luajit-buildvm -m folddef -o gen/lj_folddef.h lj_opt_fold.c
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/lj_recdef.h
COMMAND luajit-buildvm -m recdef -o gen/lj_recdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/gen/lj_libdef.h
COMMAND luajit-buildvm -m libdef -o gen/lj_libdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/vendor/luajit/src/jit/vmdef.lua
COMMAND luajit-buildvm -m vmdef -o jit/vmdef.lua lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/vendor/luajit/src
)
add_library(luajit STATIC
vendor/luajit/src/lib_base.c
vendor/luajit/src/lib_math.c
vendor/luajit/src/lib_bit.c
vendor/luajit/src/lib_string.c
vendor/luajit/src/lib_table.c
vendor/luajit/src/lib_io.c
vendor/luajit/src/lib_os.c
vendor/luajit/src/lib_package.c
vendor/luajit/src/lib_debug.c
vendor/luajit/src/lib_jit.c
vendor/luajit/src/lib_ffi.c
vendor/luajit/src/lj_gc.c
vendor/luajit/src/lj_err.c
vendor/luajit/src/lj_char.c
vendor/luajit/src/lj_bc.c
vendor/luajit/src/lj_obj.c
vendor/luajit/src/lj_buf.c
vendor/luajit/src/lj_str.c
vendor/luajit/src/lj_tab.c
vendor/luajit/src/lj_func.c
vendor/luajit/src/lj_udata.c
vendor/luajit/src/lj_meta.c
vendor/luajit/src/lj_debug.c
vendor/luajit/src/lj_state.c
vendor/luajit/src/lj_dispatch.c
vendor/luajit/src/lj_vmevent.c
vendor/luajit/src/lj_vmmath.c
vendor/luajit/src/lj_strscan.c
vendor/luajit/src/lj_strfmt.c
vendor/luajit/src/lj_strfmt_num.c
vendor/luajit/src/lj_api.c
vendor/luajit/src/lj_profile.c
vendor/luajit/src/lj_lex.c
vendor/luajit/src/lj_parse.c
vendor/luajit/src/lj_bcread.c
vendor/luajit/src/lj_bcwrite.c
vendor/luajit/src/lj_load.c
vendor/luajit/src/lj_ir.c
vendor/luajit/src/lj_opt_mem.c
vendor/luajit/src/lj_opt_fold.c
vendor/luajit/src/lj_opt_narrow.c
vendor/luajit/src/lj_opt_dce.c
vendor/luajit/src/lj_opt_loop.c
vendor/luajit/src/lj_opt_split.c
vendor/luajit/src/lj_opt_sink.c
vendor/luajit/src/lj_mcode.c
vendor/luajit/src/lj_snap.c
vendor/luajit/src/lj_record.c
vendor/luajit/src/lj_crecord.c
vendor/luajit/src/lj_ffrecord.c
vendor/luajit/src/lj_asm.c
vendor/luajit/src/lj_trace.c
vendor/luajit/src/lj_gdbjit.c
vendor/luajit/src/lj_ctype.c
vendor/luajit/src/lj_cdata.c
vendor/luajit/src/lj_cconv.c
vendor/luajit/src/lj_ccall.c
vendor/luajit/src/lj_ccallback.c
vendor/luajit/src/lj_carith.c
vendor/luajit/src/lj_clib.c
vendor/luajit/src/lj_cparse.c
vendor/luajit/src/lj_lib.c
vendor/luajit/src/lj_alloc.c
vendor/luajit/src/lib_aux.c
vendor/luajit/src/lib_init.c
vendor/luajit/src/gen/lj_ffdef.h
vendor/luajit/src/gen/lj_bcdef.h
vendor/luajit/src/gen/lj_folddef.h
vendor/luajit/src/gen/lj_recdef.h
vendor/luajit/src/gen/lj_libdef.h
vendor/luajit/src/jit/vmdef.lua
)
target_compile_definitions(luajit PRIVATE LUAJIT_ENABLE_LUA52COMPAT)
target_include_directories(luajit PRIVATE vendor/luajit/src/gen)
if(MSVC)
target_sources(luajit PRIVATE vendor/luajit/src/lj_vm.obj)
else()
target_sources(luajit PRIVATE vendor/luajit/src/lj_vm.s)
set_property(SOURCE vendor/luajit/src/lj_vm.s PROPERTY LANGUAGE C)
target_link_libraries(luajit ${CMAKE_DL_LIBS})
endif()
add_library(resrc STATIC
src/libresrc/bitmap.cpp
src/libresrc/default_config.cpp
src/libresrc/libresrc.cpp
)
add_library(csri STATIC
vendor/csri/lib/list.c
vendor/csri/lib/wrap.c
vendor/csri/subhelp/logging.c
)
target_include_directories(csri PRIVATE "vendor/csri/include")
if(WIN32)
target_include_directories(csri PRIVATE "vendor/csri/lib/win32")
target_sources(csri PRIVATE vendor/csri/lib/win32/enumerate.c)
else()
target_include_directories(csri PRIVATE "vendor/csri/lib/posix")
target_sources(csri PRIVATE vendor/csri/lib/posix/enumerate.c)
endif()
add_executable(Aegisub WIN32
src/command/app.cpp
src/command/audio.cpp
src/command/automation.cpp
src/command/command.cpp
src/command/edit.cpp
src/command/grid.cpp
src/command/help.cpp
src/command/keyframe.cpp
src/command/recent.cpp
src/command/subtitle.cpp
src/command/time.cpp
src/command/timecode.cpp
src/command/tool.cpp
src/command/video.cpp
src/command/vis_tool.cpp
src/dialog_about.cpp
src/dialog_align.cpp
src/dialog_attachments.cpp
src/dialog_automation.cpp
src/dialog_autosave.cpp
src/dialog_colorpicker.cpp
src/dialog_detached_video.cpp
src/dialog_dummy_video.cpp
src/dialog_export.cpp
src/dialog_export_ebu3264.cpp
src/dialog_fonts_collector.cpp
src/dialog_jumpto.cpp
src/dialog_kara_timing_copy.cpp
src/dialog_log.cpp
src/dialog_paste_over.cpp
src/dialog_progress.cpp
src/dialog_properties.cpp
src/dialog_resample.cpp
src/dialog_search_replace.cpp
src/dialog_selected_choices.cpp
src/dialog_selection.cpp
src/dialog_shift_times.cpp
src/dialog_spellchecker.cpp
src/dialog_style_editor.cpp
src/dialog_style_manager.cpp
src/dialog_styling_assistant.cpp
src/dialog_text_import.cpp
src/dialog_timing_processor.cpp
src/dialog_translation.cpp
src/dialog_video_details.cpp
src/dialog_video_properties.cpp
src/subtitle_format.cpp
src/subtitle_format_ass.cpp
src/subtitle_format_ebu3264.cpp
src/subtitle_format_encore.cpp
src/subtitle_format_microdvd.cpp
src/subtitle_format_mkv.cpp
src/subtitle_format_srt.cpp
src/subtitle_format_ssa.cpp
src/subtitle_format_transtation.cpp
src/subtitle_format_ttxt.cpp
src/subtitle_format_txt.cpp
src/visual_tool.cpp
src/visual_tool_clip.cpp
src/visual_tool_cross.cpp
src/visual_tool_drag.cpp
src/visual_tool_rotatexy.cpp
src/visual_tool_rotatez.cpp
src/visual_tool_scale.cpp
src/visual_tool_vector_clip.cpp
src/MatroskaParser.c
src/aegisublocale.cpp
src/ass_attachment.cpp
src/ass_dialogue.cpp
src/ass_entry.cpp
src/ass_export_filter.cpp
src/ass_exporter.cpp
src/ass_file.cpp
src/ass_karaoke.cpp
src/ass_override.cpp
src/ass_parser.cpp
src/ass_style.cpp
src/ass_style_storage.cpp
src/async_video_provider.cpp
src/audio_box.cpp
src/audio_colorscheme.cpp
src/audio_controller.cpp
src/audio_display.cpp
src/audio_karaoke.cpp
src/audio_marker.cpp
src/audio_player.cpp
src/audio_provider_factory.cpp
src/audio_renderer.cpp
src/audio_renderer_spectrum.cpp
src/audio_renderer_waveform.cpp
src/audio_timing_dialogue.cpp
src/audio_timing_karaoke.cpp
src/auto4_base.cpp
src/auto4_lua.cpp
src/auto4_lua_assfile.cpp
src/auto4_lua_dialog.cpp
src/auto4_lua_progresssink.cpp
src/base_grid.cpp
src/charset_detect.cpp
src/colorspace.cpp
src/colour_button.cpp
src/compat.cpp
src/context.cpp
src/export_fixstyle.cpp
src/export_framerate.cpp
src/fft.cpp
src/font_file_lister.cpp
src/frame_main.cpp
src/gl_text.cpp
src/gl_wrap.cpp
src/grid_column.cpp
src/help_button.cpp
src/hotkey.cpp
src/hotkey_data_view_model.cpp
src/image_position_picker.cpp
src/initial_line_state.cpp
src/main.cpp
src/menu.cpp
src/mkv_wrap.cpp
src/pen.cpp
src/persist_location.cpp
src/preferences.cpp
src/preferences_base.cpp
src/project.cpp
src/resolution_resampler.cpp
src/search_replace_engine.cpp
src/selection_controller.cpp
src/spellchecker.cpp
src/spline.cpp
src/spline_curve.cpp
src/string_codec.cpp
src/subs_controller.cpp
src/subs_edit_box.cpp
src/subs_edit_ctrl.cpp
src/subs_preview.cpp
src/subtitles_provider.cpp
src/subtitles_provider_libass.cpp
src/text_file_reader.cpp
src/text_file_writer.cpp
src/text_selection_controller.cpp
src/thesaurus.cpp
src/timeedit_ctrl.cpp
src/toggle_bitmap.cpp
src/toolbar.cpp
src/tooltip_manager.cpp
src/utils.cpp
src/validators.cpp
src/vector2d.cpp
src/version.cpp
src/video_box.cpp
src/video_controller.cpp
src/video_display.cpp
src/video_frame.cpp
src/video_out_gl.cpp
src/video_provider_cache.cpp
src/video_provider_dummy.cpp
src/video_provider_manager.cpp
src/video_provider_yuv4mpeg.cpp
src/video_slider.cpp
src/visual_feature.cpp
)
target_link_libraries(Aegisub ${CMAKE_DL_LIBS} libaegisub luabins luajit resrc csri)
target_compile_definitions(Aegisub PRIVATE CMAKE_BUILD)
set(WITH_BUILD_CREDIT OFF CACHE BOOL "Whether show build credit in about dialog")
if(WITH_BUILD_CREDIT)
set(BUILD_CREDIT "" CACHE STRING "Build credit shown in about dialog")
target_compile_definitions(Aegisub PRIVATE "BUILD_CREDIT=${BUILD_CREDIT}")
else()
unset(BUILD_CREDIT CACHE)
endif()
if(MSVC)
set_target_properties(libaegisub PROPERTIES COMPILE_FLAGS "/Yu${PROJECT_SOURCE_DIR}/libaegisub/lagi_pre.h" COMPILE_FLAGS "/FI${PROJECT_SOURCE_DIR}/libaegisub/lagi_pre.h")
else()
target_compile_options(libaegisub PRIVATE -include "${PROJECT_SOURCE_DIR}/libaegisub/lagi_pre.h")
endif()
if(MSVC)
add_definitions("/DNOMINMAX /MP /DINITGUID")
set_target_properties(Aegisub PROPERTIES COMPILE_FLAGS "/Yu${PROJECT_SOURCE_DIR}/src/agi_pre.h" COMPILE_FLAGS "/FI${PROJECT_SOURCE_DIR}/src/agi_pre.h")
target_link_libraries(Aegisub Usp10)
#target_sources(Aegisub PRIVATE src/res/res.rc src/res/strings.rc src/crash_writer_minidump.cpp)
target_sources(Aegisub PRIVATE src/res/res.rc src/res/strings.rc src/crash_writer.cpp src/dpi_aware.manifest)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Aegisub)
else()
target_sources(Aegisub PRIVATE src/crash_writer.cpp)
target_compile_options(Aegisub PRIVATE -include "${PROJECT_SOURCE_DIR}/src/agi_pre.h")
endif()
if(WIN32)
target_sources(Aegisub PRIVATE src/font_file_lister_gdi.cpp)
else()
find_package(Fontconfig REQUIRED)
target_include_directories(Aegisub PRIVATE ${Fontconfig_INCLUDE_DIRS})
target_link_libraries(Aegisub ${Fontconfig_LIBRARIES})
target_sources(Aegisub PRIVATE src/font_file_lister_fontconfig.cpp)
endif()
find_package(ass REQUIRED)
target_include_directories(Aegisub PRIVATE ${ass_INCLUDE_DIRS})
target_link_libraries(Aegisub ${ass_LIBRARIES})
find_package(Boost REQUIRED chrono filesystem locale regex system thread)
target_include_directories(libaegisub PRIVATE ${Boost_INCLUDE_DIRS})
target_include_directories(Aegisub PRIVATE ${Boost_INCLUDE_DIRS})
target_link_directories(Aegisub PRIVATE ${Boost_LIBRARY_DIRS})
target_link_libraries(Aegisub ${Boost_LIBRARIES})
find_package(OpenGL REQUIRED)
target_include_directories(Aegisub PRIVATE ${OPENGL_INCLUDE_DIR})
target_link_libraries(Aegisub ${OPENGL_LIBRARIES})
find_package(Iconv REQUIRED)
target_compile_definitions(libaegisub PRIVATE "HAVE_ICONV")
target_include_directories(libaegisub PRIVATE ${Iconv_INCLUDE_DIRS})
target_link_libraries(libaegisub ${Iconv_LIBRARIES})
if(NOT Iconv_IS_BUILT_IN)
target_compile_definitions(libaegisub PRIVATE "AGI_ICONV_CONST")
endif()
find_package(ICU REQUIRED uc dt in)
target_include_directories(libaegisub PRIVATE ${ICU_INCLUDE_DIRS})
target_include_directories(Aegisub PRIVATE ${ICU_INCLUDE_DIRS})
target_link_libraries(Aegisub ${ICU_LIBRARIES})
find_package(wxWidgets REQUIRED adv base core gl stc xml)
include(${wxWidgets_USE_FILE})
target_link_libraries(Aegisub ${wxWidgets_LIBRARIES})
find_package(ZLIB REQUIRED)
target_include_directories(Aegisub PRIVATE ${ZLIB_INCLUDE_DIRS})
target_link_libraries(Aegisub ${ZLIB_LIBRARIES})
set(WITH_ALSA ON CACHE BOOL "Enable ALSA support")
if(WITH_ALSA)
find_package(ALSA)
if(NOT ALSA_FOUND)
set(WITH_ALSA OFF CACHE BOOL "Enable ALSA support" FORCE)
endif()
endif()
if(WITH_ALSA)
target_compile_definitions(Aegisub PRIVATE "WITH_ALSA")
target_include_directories(Aegisub PRIVATE ${ALSA_INCLUDE_DIRS})
target_link_libraries(Aegisub ${ALSA_LIBRARIES})
target_sources(Aegisub PRIVATE src/audio_player_alsa.cpp)
endif()
set(WITH_AVISYNTH ON CACHE BOOL "Enable AviSynth support")
if(WITH_AVISYNTH)
find_package(AviSynth)
if(NOT AviSynth_FOUND)
set(WITH_AVISYNTH OFF CACHE BOOL "Enable AviSynth support" FORCE)
endif()
endif()
if(WITH_AVISYNTH)
target_compile_definitions(Aegisub PRIVATE "WITH_AVISYNTH" "AVS_LINKAGE_DLLIMPORT")
target_include_directories(Aegisub PRIVATE ${AviSynth_INCLUDE_DIRS})
target_link_libraries(Aegisub Vfw32 ${AviSynth_LIBRARIES})
target_sources(Aegisub PRIVATE src/audio_provider_avs.cpp src/avisynth_wrap.cpp src/video_provider_avs.cpp)
endif()
set(WITH_CSRI ON CACHE BOOL "Enable CSRI support")
if(WITH_CSRI)
target_compile_definitions(Aegisub PRIVATE "WITH_CSRI")
target_include_directories(Aegisub PRIVATE "${PROJECT_SOURCE_DIR}/vendor/csri/include")
target_sources(Aegisub PRIVATE src/subtitles_provider_csri.cpp)
endif()
if(WIN32)
target_compile_definitions(Aegisub PRIVATE "WITH_DIRECTSOUND")
target_link_libraries(Aegisub dsound)
target_sources(Aegisub PRIVATE src/audio_player_dsound.cpp src/audio_player_dsound2.cpp)
set(WITH_DIRECTSOUND ON)
else()
set(WITH_DIRECTSOUND OFF)
endif()
set(WITH_FFMS2 ON CACHE BOOL "Enable FFMS2 support")
if(WITH_FFMS2)
find_package(FFMS2)
if(NOT FFMS2_FOUND)
set(WITH_FFMS2 OFF CACHE BOOL "Enable FFMS2 support" FORCE)
endif()
endif()
if(WITH_FFMS2)
target_compile_definitions(Aegisub PRIVATE "WITH_FFMS2")
target_include_directories(Aegisub PRIVATE ${FFMS2_INCLUDE_DIRS})
target_link_libraries(Aegisub ${FFMS2_LIBRARIES})
target_sources(Aegisub PRIVATE src/audio_provider_ffmpegsource.cpp src/ffmpegsource_common.cpp src/video_provider_ffmpegsource.cpp)
else()
message(SEND_ERROR
"No supported video/audio reader interface was enabled.\n"
"You will not be able to open any video or audio files in Aegisub unless you install a supported video/audio provider.\n"
"You will however still be able to open \"dummy\" video, ie. a blank, virtual video clip with subtitles overlaid.\n"
"Currently we only support one video/audio provider on non-Windows systems:\n"
" - FFMS2\n"
" * http://github.com/FFMS/ffms2\n"
)
endif()
set(WITH_FFTW3 ON CACHE BOOL "Enable fftw support")
if(WITH_FFTW3)
find_package(FFTW)
if(NOT FFTW_FOUND)
set(WITH_FFTW3 OFF CACHE BOOL "Enable fftw support" FORCE)
endif()
endif()
if(WITH_FFTW3)
target_compile_definitions(Aegisub PRIVATE "WITH_FFTW3")
target_include_directories(Aegisub PRIVATE ${FFTW_INCLUDES})
target_link_libraries(Aegisub ${FFTW_LIBRARIES})
endif()
set(WITH_HUNSPELL ON CACHE BOOL "Enable Hunspell support")
if(WITH_HUNSPELL)
find_package(Hunspell)
if(NOT HUNSPELL_FOUND)
set(WITH_HUNSPELL OFF CACHE BOOL "Enable Hunspell support" FORCE)
endif()
endif()
if(WITH_HUNSPELL)
target_compile_definitions(Aegisub PRIVATE "WITH_HUNSPELL")
target_include_directories(Aegisub PRIVATE ${HUNSPELL_INCLUDE_DIR})
target_link_libraries(Aegisub ${HUNSPELL_LIBRARIES})
target_sources(Aegisub PRIVATE src/spellchecker_hunspell.cpp)
if(HUNSPELL_HAS_STRING_API)
target_compile_definitions(Aegisub PRIVATE "HUNSPELL_HAS_STRING_API")
endif(HUNSPELL_HAS_STRING_API)
endif()
set(WITH_LIBPULSE ON CACHE BOOL "Enable PulseAudio support")
if(WITH_LIBPULSE)
find_package(PulseAudio)
if(NOT PULSEAUDIO_FOUND)
set(WITH_LIBPULSE OFF CACHE BOOL "Enable PulseAudio support" FORCE)
endif()
endif()
if(WITH_LIBPULSE)
target_compile_definitions(Aegisub PRIVATE "WITH_LIBPULSE")
target_include_directories(Aegisub PRIVATE ${PULSEAUDIO_INCLUDE_DIR})
target_link_libraries(Aegisub ${PULSEAUDIO_LIBRARY})
target_sources(Aegisub PRIVATE src/audio_player_pulse.cpp)
endif()
set(WITH_OPENAL ON CACHE BOOL "Enable OpenAL support")
if(WITH_OPENAL)
find_package(OpenAL)
if(NOT OPENAL_FOUND)
set(WITH_OPENAL OFF CACHE BOOL "Enable OpenAL support" FORCE)
endif()
endif()
if(WITH_OPENAL)
target_compile_definitions(Aegisub PRIVATE "WITH_OPENAL")
target_include_directories(Aegisub PRIVATE ${OPENAL_INCLUDE_DIR})
target_link_libraries(Aegisub ${OPENAL_LIBRARY})
target_sources(Aegisub PRIVATE src/audio_player_openal.cpp)
endif()
set(WITH_OSS OFF CACHE BOOL "Enable OSS support")
if(WITH_OSS)
find_package(OSS)
if(NOT OSS_FOUND)
set(WITH_OSS OFF CACHE BOOL "Enable OSS support" FORCE)
endif()
endif()
if(WITH_OSS)
target_compile_definitions(Aegisub PRIVATE "WITH_OSS")
target_include_directories(Aegisub PRIVATE ${OSS_INCLUDE_DIRS})
target_sources(Aegisub PRIVATE src/audio_player_oss.cpp)
endif()
set(WITH_PORTAUDIO ON CACHE BOOL "Enable PortAudio support")
if(WITH_PORTAUDIO)
find_package(PortAudio)
if(NOT PortAudio_FOUND)
set(WITH_PORTAUDIO OFF CACHE BOOL "Enable PortAudio support" FORCE)
endif()
endif()
if(WITH_PORTAUDIO)
target_compile_definitions(Aegisub PRIVATE "WITH_PORTAUDIO")
target_include_directories(Aegisub PRIVATE ${PortAudio_INCLUDE_DIRS})
target_link_libraries(Aegisub ${PortAudio_LIBRARIES})
target_sources(Aegisub PRIVATE src/audio_player_portaudio.cpp)
endif()
set(WITH_STARTUPLOG OFF CACHE BOOL "Enable startup log")
if(WITH_STARTUPLOG)
target_compile_definitions(Aegisub PRIVATE "WITH_STARTUPLOG")
endif()
set(WITH_UCHARDET ON CACHE BOOL "Enable uchardet support")
if(WITH_UCHARDET)
find_package(uchardet)
if(NOT uchardet_FOUND)
set(WITH_UCHARDET OFF CACHE BOOL "Enable uchardet support" FORCE)
endif()
endif()
if(WITH_UCHARDET)
target_compile_definitions(Aegisub PRIVATE "WITH_UCHARDET")
target_include_directories(Aegisub PRIVATE ${uchardet_INCLUDE_DIRS})
target_link_libraries(Aegisub ${uchardet_LIBRARIES})
endif()
set(WITH_UPDATE_CHECKER OFF)
if(WITH_UPDATE_CHECKER)
set(UPDATE_CHECKER_SERVER "\"updates.aegisub.org\"" CACHE STRING "Server for the update checker")
set(UPDATE_CHECKER_BASE_URL "\"/trunk\"" CACHE STRING "Base path for the update checker")
target_compile_definitions(Aegisub PRIVATE "WITH_UPDATE_CHECKER" "UPDATE_CHECKER_SERVER=${UPDATE_CHECKER_SERVER}" "UPDATE_CHECKER_BASE_URL=${UPDATE_CHECKER_BASE_URL}")
target_link_libraries(Aegisub ${Boost_asio_LIBRARY})
target_sources(Aegisub PRIVATE src/dialog_version_check.cpp)
endif()
if(WIN32)
set(DEFAULT_PLAYER_AUDIO DirectSound)
configure_file("src/libresrc/default_config_win.json" "${PROJECT_SOURCE_DIR}/src/libresrc/default_config_platform.json" COPYONLY)
else()
if(WITH_LIBPULSE)
set(DEFAULT_PLAYER_AUDIO "PulseAudio" CACHE STRING "Default audio player")
elseif(WITH_ALSA)
set(DEFAULT_PLAYER_AUDIO "ALSA" CACHE STRING "Default audio player")
elseif(WITH_OPENAL)
set(DEFAULT_PLAYER_AUDIO "OpenAL" CACHE STRING "Default audio player")
elseif(WITH_PORTAUDIO)
set(DEFAULT_PLAYER_AUDIO "PortAudio" CACHE STRING "Default audio player")
elseif(WITH_OSS)
set(DEFAULT_PLAYER_AUDIO "OSS" CACHE STRING "Default audio player")
else()
message(SEND_ERROR
"No supported audio player interface was enabled.\n"
"If you want audio support in Aegisub you need to install one of these libraries:\n"
" - PulseAudio\n"
" * http://pulseaudio.org/\n"
" - ALSA (Linux only)\n"
" * http://www.alsa-project.org/\n"
" - PortAudio (version 19 only)\n"
" * http://www.portaudio.com/\n"
"\n"
)
set(DEFAULT_PLAYER_AUDIO "NONE" CACHE STRING "Default audio player")
endif()
add_custom_command(
OUTPUT ${PROJECT_SOURCE_DIR}/src/libresrc/default_config_platform.json
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/src/libresrc/default_config_win.json ${PROJECT_SOURCE_DIR}/src/libresrc/default_config_platform.json
)
configure_file("src/libresrc/default_config_platform.json.in" "${PROJECT_SOURCE_DIR}/src/libresrc/default_config_platform.json" @ONLY)
endif()
if(NOT WIN32)
set(AEGISUB_COMMAND "aegisub" CACHE STRING "The executable name of Aegisub")
set_target_properties(Aegisub PROPERTIES OUTPUT_NAME "${AEGISUB_COMMAND}")
configure_file("packages/desktop/aegisub.desktop.template.in" "aegisub.desktop" @ONLY)
install(FILES "${CMAKE_BINARY_DIR}/aegisub.desktop" DESTINATION "share/applications")
install(FILES "packages/desktop/16x16.png" DESTINATION "share/icons/hicolor/16x16/apps" RENAME aegisub.png)
install(FILES "packages/desktop/22x22.png" DESTINATION "share/icons/hicolor/22x22/apps" RENAME aegisub.png)
install(FILES "packages/desktop/24x24.png" DESTINATION "share/icons/hicolor/24x24/apps" RENAME aegisub.png)
install(FILES "packages/desktop/32x32.png" DESTINATION "share/icons/hicolor/32x32/apps" RENAME aegisub.png)
install(FILES "packages/desktop/48x48.png" DESTINATION "share/icons/hicolor/48x48/apps" RENAME aegisub.png)
install(FILES "packages/desktop/64x64.png" DESTINATION "share/icons/hicolor/64x64/apps" RENAME aegisub.png)
install(FILES "packages/desktop/scalable.svg" DESTINATION "share/icons/hicolor/scalable/apps" RENAME aegisub.svg)
endif()
install(TARGETS Aegisub DESTINATION bin)
set(WITH_TEST OFF CACHE BOOL "Enable unit tests")
if(WITH_TEST)
include("CMakeLists.test.txt")
endif()
message(STATUS "\n"
"Configure settings\n"
" Install prefix: ${CMAKE_INSTALL_PREFIX}\n"
" CFLAGS ${CMAKE_C_FLAGS}\n"
" CXXFLAGS ${CMAKE_CXX_FLAGS}\n"
"\n"
"Default Settings\n"
" Audio Player: ${DEFAULT_PLAYER_AUDIO}\n"
"\n"
"Audio Players\n"
" ALSA: ${WITH_ALSA}\n"
" DirectSound: ${WITH_DIRECTSOUND}\n"
" DirectSound-old: ${WITH_DIRECTSOUND}\n"
" OpenAL: ${WITH_OPENAL}\n"
" OSS: ${WITH_OSS}\n"
" PortAudio: ${WITH_PORTAUDIO}\n"
" PulseAudio: ${WITH_LIBPULSE}\n"
"\n"
"Misc Packages\n"
" AviSynth: ${WITH_AVISYNTH}\n"
" CSRI: ${WITH_CSRI}\n"
" FFMS2: ${WITH_FFMS2}\n"
" FFTW3: ${WITH_FFTW3}\n"
" Hunspell: ${WITH_HUNSPELL}\n"
" uchardet: ${WITH_UCHARDET}\n"
" LuaJIT: bundled\n"
"\n"
"Options\n"
" Startup log: ${WITH_STARTUPLOG}\n"
" Update checker: ${WITH_UPDATE_CHECKER}\n"
" Tests: ${WITH_TEST}\n"
"\n"
)

View File

@ -54,6 +54,7 @@ P_BINDIR = @bindir@
P_DATAROOT = @datarootdir@
P_LOCALE = @localedir@
P_APPDATA = @P_APPDATA@
P_DESKTOP = @P_DESKTOP@
P_ICON = @P_ICON@
P_DATA = $(P_DATAROOT)/aegisub/

View File

@ -1,85 +1,40 @@
[![Build Status](https://travis-ci.org/wangqr/Aegisub.svg?branch=dev)](https://travis-ci.org/wangqr/Aegisub)
# Aegisub
For binaries and general information [see the homepage](http://www.aegisub.org).
The bug tracker can be found at http://devel.aegisub.org.
The bug tracker can be found at https://github.com/Aegisub/Aegisub/issues .
Support is available on [the forums](http://forum.aegisub.org) or [on IRC](irc://irc.rizon.net/aegisub).
Support is available on IRC ( irc://irc.rizon.net/aegisub ).
## Building Aegisub
### Windows
Prerequisites:
1. Visual Studio 2015 (the free Community edition is good enough)
2. The June 2010 DirectX SDK (the final release before DirectSound was dropped)
3. [Yasm](http://yasm.tortall.net/) installed to somewhere on your path.
There are a few optional dependencies:
1. msgfmt, to build the translations
2. WinRAR, to build the portable installer
3. InnoSetup, to build the regular installer
All other dependencies are either stored in the repository or are included as submodules.
1. CMake 3.14 or later (or you can use an older version by editing the first line in CMakeLists.txt, and download the missing `cmake/FindFontconfig.cmake` from [here](https://gitlab.kitware.com/cmake/cmake/blob/master/Modules/FindFontconfig.cmake)),
2. Any compiling toolchain supported by CMake,
3. All required dependencies, namely `libass`, `Boost`(with ICU support), `OpenGL`, `libicu`, `wxWidgets`, `zlib`. Additionally, `libiconv` is required on non-POSIX systems. `fontconfig` is required on non-Windows systems.
4. Any optional dependencies, namely `ALSA`, `FFMS2`, `FFTW`, `Hunspell`, `OpenAL`, `uchardet`.
Building:
1. Clone Aegisub's repository recursively to fetch it and all submodules: `git clone --recursive git@github.com:Aegisub/Aegisub.git` This will take quite a while and requires about 2.5 GB of disk space.
2. Open Aegisub.sln
3. Build the BuildTasks project.
4. Build the entire solution.
You should now have a `bin` directory in your Aegisub directory which contains `aegisub32d.exe`, along with a pile of other files.
The Aegisub installer includes some files not built as part of Aegisub (such as Avisynth and VSFilter), so for a fully functional copy of Aegisub you now need to copy all of the files from an installed copy of Aegisub into your `bin` directory (and don't overwrite any of the files already there).
You'll also either need to copy the `automation` directory into the `bin` directory, or edit your automation search paths to include the `automation` directory in the source tree.
After building the solution once, you'll want to switch to the Debug-MinDep configuration, which skips checking if the dependencies are out of date, as that takes a while.
### OS X
A vaguely recent version of Xcode and the corresponding command-line tools are required.
Nothing older than Xcode 5 has been tested recently, but it is likely that some later versions of Xcode 4 are good enough.
For personal usage, you can use homebrew to install almost all of Aegisub's dependencies:
brew install autoconf ffmpeg freetype gettext ffms2 fftw fribidi libass m4
brew install --devel --with-gc64 luajit
brew install --HEAD icu4c
brew link --force icu4c
brew link --force gettext
brew install --HEAD --c++11 --with-icu4c boost
wxWidgets is located in vendor/wxWidgets, and can be built like so:
CPPFLAGS="$CPPFLAGS -D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=1" \
./configure --disable-aboutdlg --disable-animatectrl --disable-aui --disable-any \
--disable-bannerwindow --disable-base64 --disable-calendar --disable-caret \
--disable-cmdline --disable-colourpicker --disable-compat28 --disable-config \
--disable-constraints --disable-datepick --disable-dctransform --disable-debugreport \
--disable-dialupman --disable-docview --disable-filehistory --disable-finddlg \
--disable-fs_archive --disable-fs_inet --disable-fs_zip --disable-fsvolume \
--disable-fswatcher --disable-gif --disable-help --disable-html --disable-ipc \
--disable-joystick --disable-jpeg --disable-largefile --disable-markup --disable-mdi \
--disable-mediactrl --disable-metafiles --disable-miniframe --disable-notifmsg \
--disable-numberdlg --disable-pcx --disable-pnm --disable-postscript \
--disable-prefseditor --disable-printarch --disable-progressdlg --disable-propgrid \
--disable-protocol --disable-protocols --disable-rearrangectrl --disable-ribbon \
--disable-richtext --disable-richtooltip --disable-snglinst --disable-sockets \
--disable-sockets --disable-sound --disable-splash --disable-splines \
--disable-std_iostreams --disable-svg --disable-tarstream --disable-tiff \
--disable-tipdlg --disable-tipwindow --disable-url --disable-webkit --disable-webview \
--disable-wizarddlg --disable-xrc \
--enable-geometry --enable-imaglist --enable-listctrl --enable-stc --with-cocoa \
--with-libpng=yes --with-macosx-version-min=10.9 \
--with-opengl \
--without-libjpeg --without-libtiff --without-regex \
&& make
Once the dependencies are installed, build Aegisub with `autoreconf && ./configure --with-wxdir=/path/to/Aegisub/vendor/wxWidgets && make && make osx-bundle`.
`autoreconf` should be skipped if you are building from a source tarball rather than `git`.
1. If you decided to build from source:
```shell
git clone https://github.com/wangqr/Aegisub.git # No --recursive is needed
cd Aegisub
./build/version.sh . # This will generate build/git_version.h
```
2. Make an empty directory to hold build outputs:
```shell
mkdir build-dir
```
3. Build the project using CMake. Use either cmake-gui, or the command line:
```shell
cd build-dir
cmake ..
make
```
## Updating Moonscript
@ -95,4 +50,4 @@ The file is now ready for use, to be placed in `automation/include` within the A
## License
All files in this repository are licensed under various GPL-compatible BSD-style licenses; see LICENCE and the individual source files for more information.
The official Windows and OS X builds are GPLv2 due to including fftw3.
The official Windows build is GPLv2 due to including fftw3.

View File

@ -39,7 +39,7 @@ search = (re, str, start) ->
res = regex.search re, str, str\len(), start
return unless res != nil
first, last = res[0], res[1]
ffi.C.free res
ffi.gc(res, ffi.C.free)
first, last
replace = (re, replacement, str, max_count) ->

View File

@ -53,7 +53,7 @@ int main(int argc, char **argv) {
agi::log::log = new agi::log::LogSink;
// Init lua state
lua_State *L = lua_open();
lua_State *L = luaL_newstate();
if (!L) {
fprintf(stderr, "Failed to create Lua state\n");
return 1;

View File

@ -40,3 +40,11 @@ Returns: 2 values, all numbers.
2. End of the selection, in milliseconds.
---
Setting the main frame's status bar text
function aegisub.set_status_bar_text(text)
Returns: 0 values
---

View File

@ -30,6 +30,9 @@
<AdditionalLibraryDirectories Condition="'$(Platform)'=='Win32'">$(DXSDK_DIR)\Lib\x86</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories Condition="'$(Platform)'=='x64'">$(DXSDK_DIR)\Lib\x64</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<!-- Update git_version.h -->

20
cmake/FindAviSynth.cmake Normal file
View File

@ -0,0 +1,20 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_AviSynth QUIET AviSynth)
find_path(AviSynth_INCLUDE_DIRS
NAMES avisynth.h
HINTS ${PC_AviSynth_INCLUDE_DIRS}
)
find_library(AviSynth_LIBRARIES
NAMES avisynth
PATH_SUFFIXES c_api
HINTS ${PC_AviSynth_LIBRARY_DIRS}
)
set(AviSynth_VERSION ${PC_AviSynth_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(AviSynth
FOUND_VAR AviSynth_FOUND
REQUIRED_VARS
AviSynth_LIBRARIES
AviSynth_INCLUDE_DIRS
VERSION_VAR AviSynth_VERSION
)

19
cmake/FindFFMS2.cmake Normal file
View File

@ -0,0 +1,19 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_FFMS2 QUIET ffms2)
find_path(FFMS2_INCLUDE_DIRS
NAMES ffms.h ffmscompat.h
HINTS ${PC_FFMS2_INCLUDE_DIRS}
)
find_library(FFMS2_LIBRARIES
NAMES ffms2
HINTS ${PC_FFMS2_LIBRARY_DIRS}
)
set(FFMS2_VERSION ${PC_FFMS2_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FFMS2
FOUND_VAR FFMS2_FOUND
REQUIRED_VARS
FFMS2_LIBRARIES
FFMS2_INCLUDE_DIRS
VERSION_VAR FFMS2_VERSION
)

119
cmake/FindFFTW.cmake Normal file
View File

@ -0,0 +1,119 @@
# - Find the FFTW library
#
# Usage:
# find_package(FFTW [REQUIRED] [QUIET] )
#
# It sets the following variables:
# FFTW_FOUND ... true if fftw is found on the system
# FFTW_LIBRARIES ... full path to fftw library
# FFTW_INCLUDES ... fftw include directory
#
# The following variables will be checked by the function
# FFTW_USE_STATIC_LIBS ... if true, only static libraries are found
# FFTW_ROOT ... if set, the libraries are exclusively searched
# under this path
# FFTW_LIBRARY ... fftw library to use
# FFTW_INCLUDE_DIR ... fftw include directory
#
#If environment variable FFTWDIR is specified, it has same effect as FFTW_ROOT
if( NOT FFTW_ROOT AND ENV{FFTWDIR} )
set( FFTW_ROOT $ENV{FFTWDIR} )
endif()
# Check if we can use PkgConfig
find_package(PkgConfig QUIET)
#Determine from PKG
if( PKG_CONFIG_FOUND AND NOT FFTW_ROOT )
pkg_check_modules( PKG_FFTW QUIET "fftw3" )
endif()
#Check whether to search static or dynamic libs
set( CMAKE_FIND_LIBRARY_SUFFIXES_SAV ${CMAKE_FIND_LIBRARY_SUFFIXES} )
if( ${FFTW_USE_STATIC_LIBS} )
set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} )
else()
set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX} )
endif()
if( FFTW_ROOT )
#find libs
find_library(
FFTW_LIB
NAMES "fftw3"
PATHS ${FFTW_ROOT}
PATH_SUFFIXES "lib" "lib64"
NO_DEFAULT_PATH
)
find_library(
FFTWF_LIB
NAMES "fftw3f"
PATHS ${FFTW_ROOT}
PATH_SUFFIXES "lib" "lib64"
NO_DEFAULT_PATH
)
find_library(
FFTWL_LIB
NAMES "fftw3l"
PATHS ${FFTW_ROOT}
PATH_SUFFIXES "lib" "lib64"
NO_DEFAULT_PATH
)
#find includes
find_path(
FFTW_INCLUDES
NAMES "fftw3.h"
PATHS ${FFTW_ROOT}
PATH_SUFFIXES "include"
NO_DEFAULT_PATH
)
else()
find_library(
FFTW_LIB
NAMES "fftw3"
PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
)
find_library(
FFTWF_LIB
NAMES "fftw3f"
PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
)
find_library(
FFTWL_LIB
NAMES "fftw3l"
PATHS ${PKG_FFTW_LIBRARY_DIRS} ${LIB_INSTALL_DIR}
)
find_path(
FFTW_INCLUDES
NAMES "fftw3.h"
PATHS ${PKG_FFTW_INCLUDE_DIRS} ${INCLUDE_INSTALL_DIR}
)
endif( FFTW_ROOT )
set(FFTW_LIBRARIES ${FFTW_LIB} ${FFTWF_LIB})
if(FFTWL_LIB)
set(FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTWL_LIB})
endif()
set( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_SAV} )
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FFTW DEFAULT_MSG
FFTW_INCLUDES FFTW_LIBRARIES)
mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES FFTW_LIB FFTWF_LIB FFTWL_LIB)

64
cmake/FindHunspell.cmake Normal file
View File

@ -0,0 +1,64 @@
# - Try to find Hunspell
# Once done this will define
#
# HUNSPELL_FOUND - system has Hunspell
# HUNSPELL_INCLUDE_DIR - the Hunspell include directory
# HUNSPELL_LIBRARIES - Link these to use Hunspell
# HUNSPELL_HAS_STRING_API - Hunspell has vector<string> api (>=1.5.1)
#
# Redistribution and use of this file is allowed according to the terms of the
# MIT license. For details see the file COPYING-CMAKE-MODULES.
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig QUIET)
pkg_check_modules(HUNSPELL_PKG QUIET hunspell)
FIND_PATH(HUNSPELL_INCLUDE_DIR NAMES hunspell.h
PATHS
/usr/local/include
/usr/include
HINTS
${HUNSPELL_PKG_INCLUDE_DIRS} # Generated by pkg-config
PATH_SUFFIXES hunspell
)
FIND_LIBRARY(HUNSPELL_LIBRARIES NAMES hunspell-1.7 hunspell-1.6 hunspell-1.5 hunspell-1.4 hunspell-1.3 hunspell-1.2 hunspell ${HUNSPELL_PKG_LIBRARIES}
PATHS
/usr/local
/usr
HINTS
${HUNSPELL_PKG_LIBRARY_DIRS} # Generated by pkg-config
PATH_SUFFIXES
lib64
lib
)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Hunspell DEFAULT_MSG HUNSPELL_LIBRARIES HUNSPELL_INCLUDE_DIR )
add_library(hunspell UNKNOWN IMPORTED)
set_target_properties(hunspell PROPERTIES IMPORTED_LOCATION ${HUNSPELL_LIBRARIES} INTERFACE_INCLUDE_DIRECTORIES ${HUNSPELL_INCLUDE_DIR})
if (NOT BUILD_SHARED_LIBS)
# At least statically compiled hunspell 1.7.0 requires HUNSPELL_STATIC
# For other versions, it should not hurt
set_target_properties(hunspell PROPERTIES INTERFACE_COMPILE_DEFINITIONS HUNSPELL_STATIC)
endif ()
if (HUNSPELL_FOUND)
try_compile(HUNSPELL_HAS_STRING_API "${CMAKE_BINARY_DIR}/hunspell_string_api"
"${CMAKE_CURRENT_LIST_DIR}/hunspell_string_api.cpp"
LINK_LIBRARIES ${HUNSPELL_LIBRARIES}
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${HUNSPELL_INCLUDE_DIR}")
if (HUNSPELL_HAS_STRING_API)
message(STATUS "Hunspell has string API")
else(HUNSPELL_HAS_STRING_API)
message(STATUS "Hunspell does not have string API")
endif(HUNSPELL_HAS_STRING_API)
endif(HUNSPELL_FOUND)
# show the HUNSPELL_INCLUDE_DIR and HUNSPELL_LIBRARIES variables only in the advanced view
MARK_AS_ADVANCED(HUNSPELL_INCLUDE_DIR HUNSPELL_LIBRARIES HUNSPELL_HAS_STRING_API)

14
cmake/FindOSS.cmake Normal file
View File

@ -0,0 +1,14 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_oss QUIET oss)
find_path(OSS_INCLUDE_DIRS
NAMES sys/soundcard.h
HINTS ${PC_oss_INCLUDE_DIRS}
)
set(OSS_VERSION ${PC_ass_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OSS
FOUND_VAR OSS_FOUND
REQUIRED_VARS
OSS_INCLUDE_DIRS
VERSION_VAR OSS_VERSION
)

19
cmake/FindPortAudio.cmake Normal file
View File

@ -0,0 +1,19 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_portaudio QUIET portaudio-2.0)
find_path(PortAudio_INCLUDE_DIRS
NAMES portaudio.h
HINTS ${PC_portaudio_INCLUDE_DIRS}
)
find_library(PortAudio_LIBRARIES
NAMES portaudio
HINTS ${PC_portaudio_LIBRARY_DIRS}
)
set(PortAudio_VERSION ${PC_portaudio_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PortAudio
FOUND_VAR PortAudio_FOUND
REQUIRED_VARS
PortAudio_LIBRARIES
PortAudio_INCLUDE_DIRS
VERSION_VAR PortAudio_VERSION
)

View File

@ -0,0 +1,70 @@
# Try to find the PulseAudio library
#
# Once done this will define:
#
# PULSEAUDIO_FOUND - system has the PulseAudio library
# PULSEAUDIO_INCLUDE_DIR - the PulseAudio include directory
# PULSEAUDIO_LIBRARY - the libraries needed to use PulseAudio
# PULSEAUDIO_MAINLOOP_LIBRARY - the libraries needed to use PulsAudio Mainloop
#
# The minimum required version of PulseAudio can be specified using the
# standard syntax, e.g. find_package(PulseAudio 1.0)
# Copyright (c) 2008, Matthias Kretz, <kretz@kde.org>
# Copyright (c) 2009, Marcus Hufgard, <Marcus.Hufgard@hufgard.de>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
# Support PULSEAUDIO_MINIMUM_VERSION for compatibility:
if(NOT PulseAudio_FIND_VERSION)
set(PulseAudio_FIND_VERSION "${PULSEAUDIO_MINIMUM_VERSION}")
endif(NOT PulseAudio_FIND_VERSION)
# the minimum version of PulseAudio we require
if(NOT PulseAudio_FIND_VERSION)
set(PulseAudio_FIND_VERSION "0.9.9")
endif(NOT PulseAudio_FIND_VERSION)
find_package(PkgConfig QUIET)
pkg_check_modules(PC_PULSEAUDIO QUIET libpulse>=${PulseAudio_FIND_VERSION})
pkg_check_modules(PC_PULSEAUDIO_MAINLOOP QUIET libpulse-mainloop-glib)
find_path(PULSEAUDIO_INCLUDE_DIR pulse/pulseaudio.h
HINTS
${PC_PULSEAUDIO_INCLUDEDIR}
${PC_PULSEAUDIO_INCLUDE_DIRS}
)
find_library(PULSEAUDIO_LIBRARY NAMES pulse libpulse
HINTS
${PC_PULSEAUDIO_LIBDIR}
${PC_PULSEAUDIO_LIBRARY_DIRS}
)
find_library(PULSEAUDIO_MAINLOOP_LIBRARY NAMES pulse-mainloop pulse-mainloop-glib libpulse-mainloop-glib
HINTS
${PC_PULSEAUDIO_LIBDIR}
${PC_PULSEAUDIO_LIBRARY_DIRS}
)
# Store the version number in the cache, so we don't have to search every time again:
if (PULSEAUDIO_INCLUDE_DIR AND NOT PULSEAUDIO_VERSION)
# get PulseAudio's version from its version.h, and compare it with our minimum version
file(STRINGS "${PULSEAUDIO_INCLUDE_DIR}/pulse/version.h" pulse_version_h
REGEX ".*pa_get_headers_version\\(\\).*"
)
string(REGEX REPLACE ".*pa_get_headers_version\\(\\)\ \\(\"([0-9]+\\.[0-9]+\\.[0-9]+)[^\"]*\"\\).*" "\\1"
_PULSEAUDIO_VERSION "${pulse_version_h}")
set(PULSEAUDIO_VERSION "${_PULSEAUDIO_VERSION}" CACHE STRING "Version number of PulseAudio" FORCE)
endif (PULSEAUDIO_INCLUDE_DIR AND NOT PULSEAUDIO_VERSION)
# Use the new extended syntax of find_package_handle_standard_args(), which also handles version checking:
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PulseAudio REQUIRED_VARS PULSEAUDIO_LIBRARY PULSEAUDIO_INCLUDE_DIR
VERSION_VAR PULSEAUDIO_VERSION )
mark_as_advanced(PULSEAUDIO_INCLUDE_DIR PULSEAUDIO_LIBRARY PULSEAUDIO_MAINLOOP_LIBRARY)

20
cmake/Findass.cmake Normal file
View File

@ -0,0 +1,20 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_ass QUIET libass)
find_path(ass_INCLUDE_DIRS
NAMES ass/ass.h ass/ass_types.h
PATH_SUFFIXES libass
HINTS ${PC_ass_INCLUDE_DIRS}
)
find_library(ass_LIBRARIES
NAMES ass
HINTS ${PC_ass_LIBRARY_DIRS}
)
set(ass_VERSION ${PC_ass_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ass
FOUND_VAR ass_FOUND
REQUIRED_VARS
ass_LIBRARIES
ass_INCLUDE_DIRS
VERSION_VAR ass_VERSION
)

20
cmake/Finduchardet.cmake Normal file
View File

@ -0,0 +1,20 @@
find_package(PkgConfig QUIET)
pkg_check_modules(PC_uchardet QUIET uchardet)
find_path(uchardet_INCLUDE_DIRS
NAMES uchardet/uchardet.h
HINTS ${PC_uchardet_INCLUDE_DIRS}
)
find_library(uchardet_LIBRARIES
NAMES uchardet
PATH_SUFFIXES build/src
HINTS ${PC_uchardet_LIBRARY_DIRS}
)
set(uchardet_VERSION ${PC_uchardet_VERSION})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(uchardet
FOUND_VAR uchardet_FOUND
REQUIRED_VARS
uchardet_LIBRARIES
uchardet_INCLUDE_DIRS
VERSION_VAR uchardet_VERSION
)

View File

@ -0,0 +1,10 @@
#include <hunspell/hunspell.hxx>
#include <string>
int main() {
Hunspell hunspell(NULL, NULL);
std::string word = "";
hunspell.suggest(word);
hunspell.spell(word);
return 0;
}

View File

@ -54,6 +54,13 @@ AEGISUB_CATALOG="aegisub"
AC_SUBST(AEGISUB_CATALOG)
AC_DEFINE_UNQUOTED([AEGISUB_CATALOG], ["${AEGISUB_CATALOG}"], [Name of the Aegisub gettext catalog])
# Handle location of appdata files: https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html#spec-component-location
AC_ARG_WITH(appdata-dir,
AS_HELP_STRING([--with-appdata-dir=PATH],[appdata file locations [PREFIX/share/metainfo]]))
P_APPDATA=${with_appdata_dir:-$datarootdir/metainfo}
AC_SUBST(P_APPDATA)
# Handle location of desktop files: http://freedesktop.org/wiki/Specifications/desktop-entry-spec
AC_ARG_WITH(desktop-dir,
AS_HELP_STRING([--with-desktop-dir=PATH],[desktop file locations [PREFIX/share/applications]]))
@ -133,20 +140,18 @@ AS_IF([test x$build_darwin != xyes], [
AC_ARG_ENABLE(compiler-flags, AS_HELP_STRING([--disable-compiler-flags],[Disable *all* additional compiler flags. [no]]))
AS_IF([test x$enable_compiler_flags != xno], [
CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter -std=gnu99 -pipe -g"
CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wno-unused-parameter -fno-strict-aliasing -pipe -g"
CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-parameter"
CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wno-unused-parameter -fno-strict-aliasing"
AC_C_FLAG([-std=gnu99])
AC_CXX_FLAG([-std=c++11])
AC_CXX_FLAG([-Wno-c++11-narrowing])
AC_CXX_FLAG([-Wno-narrowing])
AC_C_FLAG([-Wno-unused-local-typedefs])
AC_CXX_FLAG([-Wno-unused-local-typedefs])
# -O* messes with debugging.
AS_IF([test x$enable_debug = xyes], [
CFLAGS="$CFLAGS -O0"
CXXFLAGS="$CXXFLAGS -O0"
], [
CFLAGS="$CFLAGS -O3"
CXXFLAGS="$CXXFLAGS -O3"
CFLAGS="$CFLAGS -O0 -g"
CXXFLAGS="$CXXFLAGS -O0 -g"
])
])
@ -426,7 +431,7 @@ AS_IF([test x$with_system_luajit != xno], [
])
AS_IF([test $with_system_luajit = no],
[AC_SUBST([LUAJIT_CFLAGS], ['-I$(TOP)vendor/luajit/include'])
[AC_SUBST([LUAJIT_CFLAGS], ['-I$(TOP)vendor/luajit/src'])
AC_SUBST([LUAJIT_LIBS], ['$(TOP)vendor/luajit/src/libluajit.a'])])
# We also need a Lua binary to run part of the build system
@ -505,6 +510,7 @@ AC_PCH_FLAG([-fpch-preprocess])
# Internationalisation support
##############################
AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.19.7])
################
# Update checker
@ -564,6 +570,7 @@ DEFAULT_PLAYER_AUDIO=${DEFAULT_PLAYER_AUDIO:-NONE}
# Files that need substitution.
AC_CONFIG_FILES([
packages/desktop/aegisub.desktop.template
packages/desktop/aegisub.appdata.xml.template
src/libresrc/default_config_platform.json
tools/osx-bundle.sed
Makefile.inc

View File

@ -24,7 +24,7 @@
#include <algorithm>
namespace agi {
Time::Time(int time) : time(util::mid(0, time, 10 * 60 * 60 * 1000 - 1)) { }
Time::Time(int time) : time(util::mid(0, time, 10 * 60 * 60 * 1000 - 6)) { }
Time::Time(std::string const& text) {
int after_decimal = -1;
@ -56,29 +56,39 @@ Time::Time(std::string const& text) {
time = (time * 60 + current) * 1000;
// Limit to the valid range
time = util::mid(0, time, 10 * 60 * 60 * 1000 - 1);
time = util::mid(0, time, 10 * 60 * 60 * 1000 - 6);
}
std::string Time::GetAssFormatted(bool msPrecision) const {
int ass_time = msPrecision ? time : int(*this);
std::string ret(10 + msPrecision, ':');
ret[0] = '0' + GetTimeHours();
ret[2] = '0' + (time % (60 * 60 * 1000)) / (60 * 1000 * 10);
ret[3] = '0' + (time % (10 * 60 * 1000)) / (60 * 1000);
ret[5] = '0' + (time % (60 * 1000)) / (1000 * 10);
ret[6] = '0' + (time % (10 * 1000)) / 1000;
ret[0] = '0' + ass_time / 3600000;
ret[2] = '0' + (ass_time % (60 * 60 * 1000)) / (60 * 1000 * 10);
ret[3] = '0' + (ass_time % (10 * 60 * 1000)) / (60 * 1000);
ret[5] = '0' + (ass_time % (60 * 1000)) / (1000 * 10);
ret[6] = '0' + (ass_time % (10 * 1000)) / 1000;
ret[7] = '.';
ret[8] = '0' + (time % 1000) / 100;
ret[9] = '0' + (time % 100) / 10;
ret[8] = '0' + (ass_time % 1000) / 100;
ret[9] = '0' + (ass_time % 100) / 10;
if (msPrecision)
ret[10] = '0' + time % 10;
ret[10] = '0' + ass_time % 10;
return ret;
}
int Time::GetTimeHours() const { return time / 3600000; }
int Time::GetTimeMinutes() const { return (time % 3600000) / 60000; }
int Time::GetTimeSeconds() const { return (time % 60000) / 1000; }
int Time::GetTimeMiliseconds() const { return (time % 1000); }
int Time::GetTimeCentiseconds() const { return (time % 1000) / 10; }
std::string Time::GetSrtFormatted() const {
std::string ret(12, ':');
ret[0] = '0';
ret[1] = '0' + time / 3600000;
ret[3] = '0' + (time % (60 * 60 * 1000)) / (60 * 1000 * 10);
ret[4] = '0' + (time % (10 * 60 * 1000)) / (60 * 1000);
ret[6] = '0' + (time % (60 * 1000)) / (1000 * 10);
ret[7] = '0' + (time % (10 * 1000)) / 1000;
ret[8] = ',';
ret[9] = '0' + (time % 1000) / 100;
ret[10] = '0' + (time % 100) / 10;
ret[11] = '0' + time % 10;
return ret;
}
SmpteFormatter::SmpteFormatter(vfr::Framerate fps, char sep)
: fps(std::move(fps))

View File

@ -41,14 +41,14 @@ public:
void FillBuffer(void *buf, int64_t start, int64_t count64) const override {
auto count = static_cast<size_t>(count64);
assert(count == count64);
assert(count64 >= 0 && count == static_cast<uint64_t>(count64));
src_buf.resize(count * src_bytes_per_sample * channels);
source->GetAudio(src_buf.data(), start, count);
auto dest = static_cast<int16_t*>(buf);
for (int64_t i = 0; i < count * channels; ++i) {
for (size_t i = 0; i < count * channels; ++i) {
int64_t sample = 0;
// 8 bits per sample is assumed to be unsigned with a bias of 127,
@ -85,7 +85,7 @@ public:
void FillBuffer(void *buf, int64_t start, int64_t count64) const override {
auto count = static_cast<size_t>(count64);
assert(count == count64);
assert(count64 >= 0 && count == static_cast<uint64_t>(count64));
src_buf.resize(count * channels);
source->GetAudio(&src_buf[0], start, count);
@ -119,7 +119,7 @@ public:
void FillBuffer(void *buf, int64_t start, int64_t count64) const override {
auto count = static_cast<size_t>(count64);
assert(count == count64);
assert(count64 >= 0 && count == static_cast<uint64_t>(count64));
src_buf.resize(count * src_channels);
source->GetAudio(&src_buf[0], start, count);

View File

@ -77,7 +77,7 @@ void RAMAudioProvider::FillBuffer(void *buf, int64_t start, int64_t count) const
break;
}
const int i = (start * bytes_per_sample) >> CacheBits;
const size_t i = (start * bytes_per_sample) >> CacheBits;
const int start_offset = (start * bytes_per_sample) & (CacheBlockSize-1);
const int read_size = std::min<int>(bytes_remaining, CacheBlockSize - start_offset);

View File

@ -31,6 +31,8 @@ struct utext_deleter {
};
using utext_ptr = std::unique_ptr<UText, utext_deleter>;
UChar32 ass_special_chars[] = {'n', 'N', 'h'};
icu::BreakIterator& get_break_iterator(const char *ptr, size_t len) {
static std::unique_ptr<icu::BreakIterator> bi;
static std::once_flag token;
@ -65,10 +67,25 @@ size_t count_in_range(Iterator begin, Iterator end, int mask) {
UChar32 c;
int i = 0;
U8_NEXT_UNSAFE(begin + pos, i, c);
if ((U_GET_GC_MASK(c) & mask) == 0)
++count;
if ((U_GET_GC_MASK(c) & mask) == 0) {
if (mask & U_GC_Z_MASK && pos != 0) {
UChar32 *result = std::find(std::begin(ass_special_chars), std::end(ass_special_chars), c);
if (result != std::end(ass_special_chars)) {
UChar32 c2;
i = 0;
U8_PREV_UNSAFE(begin + pos, i, c2);
if (c2 != (UChar32) '\\')
++count;
else if (!(mask & U_GC_P_MASK))
--count;
}
else
++count;
}
else
++count;
}
}
}
return count;
}

View File

@ -29,37 +29,44 @@ namespace agi { namespace charset {
std::string Detect(agi::fs::path const& file) {
agi::read_file_mapping fp(file);
// FIXME: It is an empty file. Treat as ascii
if (fp.size() == 0) return "ascii";
// FIXME: Dirty hack for Matroska. These 4 bytes are the magic
// number of EBML which is used by mkv and webm
if (fp.size() >= 4) {
const char* buf = fp.read(0, 4);
if (!strncmp(buf, "\x1a\x45\xdf\xa3", 4))
return "binary";
}
#ifdef WITH_UCHARDET
agi::scoped_holder<uchardet_t> ud(uchardet_new(), uchardet_delete);
for (uint64_t offset = 0; offset < fp.size(); ) {
auto read = std::min<uint64_t>(65536, fp.size() - offset);
auto buf = fp.read(offset, read);
uchardet_handle_data(ud, buf, read);
offset += read;
}
uchardet_data_end(ud);
std::string encoding = uchardet_get_charset(ud);
return encoding.empty() ? "binary" : encoding;
#else
// Look for utf-8 BOM
if (fp.size() >= 3) {
const char* buf = fp.read(0, 3);
if (!strncmp(buf, "\xef\xbb\xbf", 3))
return "utf-8";
}
// If it's over 100 MB it's either binary or big enough that we won't
// be able to do anything useful with it anyway
if (fp.size() > 100 * 1024 * 1024)
return "binary";
uint64_t binaryish = 0;
#ifdef WITH_UCHARDET
agi::scoped_holder<uchardet_t> ud(uchardet_new(), uchardet_delete);
for (uint64_t offset = 0; offset < fp.size(); ) {
auto read = std::min<uint64_t>(4096, fp.size() - offset);
auto buf = fp.read(offset, read);
uchardet_handle_data(ud, buf, read);
uchardet_data_end(ud);
if (*uchardet_get_charset(ud))
return uchardet_get_charset(ud);
offset += read;
// A dumb heuristic to detect binary files
for (size_t i = 0; i < read; ++i) {
if ((unsigned char)buf[i] < 32 && (buf[i] != '\r' && buf[i] != '\n' && buf[i] != '\t'))
++binaryish;
}
if (binaryish > offset / 8)
return "binary";
}
return uchardet_get_charset(ud);
#else
auto read = std::min<uint64_t>(4096, fp.size());
auto read = std::min<uint64_t>(65536, fp.size());
auto buf = fp.read(0, read);
for (size_t i = 0; i < read; ++i) {
if ((unsigned char)buf[i] < 32 && (buf[i] != '\r' && buf[i] != '\n' && buf[i] != '\t'))

View File

@ -366,7 +366,7 @@ size_t IconvWrapper::RequiredBufferSize(std::string const& str) {
}
size_t IconvWrapper::RequiredBufferSize(const char* src, size_t srcLen) {
char buff[512];
char buff[65536];
size_t charsWritten = 0;
size_t res;

View File

@ -173,7 +173,7 @@ void tagless_find_helper::map_range(size_t &s, size_t &e) {
// match
for (auto const& block : blocks) {
// Any blocks before start are irrelevant as they're included in `start`
if (block.second < s) continue;
if (block.second <= start) continue;
// Skip over blocks at the very beginning of the match
// < should only happen if the cursor was within an override block
// when the user started a search

View File

@ -28,16 +28,14 @@ public:
Time(std::string const& text);
/// Get millisecond, rounded to centisecond precision
operator int() const { return time / 10 * 10; }
int GetTimeHours() const; ///< Get the hours portion of this time
int GetTimeMinutes() const; ///< Get the minutes portion of this time
int GetTimeSeconds() const; ///< Get the seconds portion of this time
int GetTimeMiliseconds() const; ///< Get the miliseconds portion of this time
int GetTimeCentiseconds() const; ///< Get the centiseconds portion of this time
// Always round up for 5ms because the range is [start, stop)
operator int() const { return (time + 5) - (time + 5) % 10; }
/// Return the time as a string
/// @param ms Use milliseconds precision, for non-ASS formats
std::string GetAssFormatted(bool ms=false) const;
/// Return the time as a string
std::string GetSrtFormatted() const;
};
}

View File

@ -53,7 +53,7 @@ namespace agi {
DEFINE_FS_EXCEPTION(FileNotFound, FileNotAccessible, "File not found: ");
/// An error of some unknown type has occured
DEFINE_EXCEPTION(FileSystemUnknownError, FileSystemError);;
DEFINE_EXCEPTION(FileSystemUnknownError, FileSystemError);
/// The path exists, but isn't a file
DEFINE_FS_EXCEPTION(NotAFile, FileNotAccessible, "Path is not a file (and should be): ");

View File

@ -1,5 +1,5 @@
#ifdef __cplusplus
#ifndef _WIN32
#if !defined(_WIN32) && !defined(CMAKE_BUILD)
#include "../acconf.h"
#endif

View File

@ -2334,7 +2334,7 @@ static int matchl (lua_State *L) {
}
static struct luaL_reg pattreg[] = {
static struct luaL_Reg pattreg[] = {
{"match", matchl},
{"print", printpat_l},
{"locale", locale_l},
@ -2360,7 +2360,7 @@ static struct luaL_reg pattreg[] = {
};
static struct luaL_reg metapattreg[] = {
static struct luaL_Reg metapattreg[] = {
{"__add", union_l},
{"__pow", star_l},
{"__sub", diff_l},

View File

@ -10,15 +10,26 @@ DESKTOP_FILE_INSTALLED = $(DESTDIR)$(P_DESKTOP)/$(notdir $(DESKTOP_FILE))
DISTCLEANFILES += $(DESKTOP_FILE)
APPDATA_FILE := $(d)aegisub.appdata.xml
APPDATA_FILE_PO := $(d)../../po
APPDATA_FILE_INSTALLED = $(DESTDIR)$(P_APPDATA)/$(notdir $(APPDATA_FILE))
DISTCLEANFILES += $(APPDATA_FILE)
%.desktop: %.desktop.template $(DESKTOP_FILE_PO)
intltool-merge --quiet --desktop-style $(DESKTOP_FILE_PO) $< $@
$(AM_V_GEN)$(BIN_MSGFMT) --desktop --template $< -o $@ $(DESKTOP_FILE_PO)
%.appdata.xml: %.appdata.xml.template $(APPDATA_FILE_PO)
intltool-merge --quiet --xml-style $(APPDATA_FILE_PO) $< $@
$(ICONS_INSTALLED)png: $(d)%.png ; $(MKDIR_INSTALL)
$(ICONS_INSTALLED)svg: $(d)%.svg ; $(MKDIR_INSTALL)
$(DESKTOP_FILE_INSTALLED): $(DESKTOP_FILE) ; $(MKDIR_INSTALL)
$(APPDATA_FILE_INSTALLED): $(APPDATA_FILE) ; $(MKDIR_INSTALL)
ifneq (yes, $(BUILD_DARWIN))
install: \
$(APPDATA_FILE_INSTALLED) \
$(DESKTOP_FILE_INSTALLED) \
$(patsubst %.png, $(ICONS_INSTALLED)png, $(patsubst %.svg, $(ICONS_INSTALLED)svg, $(notdir $(ICONS))))
endif

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>aegisub.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>BSD-3-Clause AND MIT AND MPL-1.1</project_license>
<_name>Aegisub</_name>
<_summary>A free, cross-platform open source tool for creating and modifying subtitles</_summary>
<description>
<_p>Aegisub is a free, cross-platform open source tool for creating and modifying subtitles. Aegisub makes it quick and easy to time subtitles to audio, and features many powerful tools for styling them, including a built-in real-time video preview.</_p>
<_p>Aegisub was originally created as a tool to make typesetting, particularly in anime fansubs, a less painful experience. At the time of the start of the project, many other programs that supported the Advanced Substation Alpha format lacked (and in many cases, still lack; development on several competing programs have since been dropped for various reasons completely unrelated to Aegisub) many vital functions, or were too buggy and/or unreliable to be really useful.</_p>
<_p>Since then, Aegisub has grown into a fully fledged, highly customizable subtitle editor. It features a lot of convenient tools to help you with timing, typesetting, editing and translating subtitles, as well as a powerful scripting environment called Automation (originally mostly intended for creating karaoke effects, Automation can now be used much else, including creating macros and various other convenient tools).</_p>
<_p>Some highlights of Aegisub:</_p>
<ul>
<_li>Simple and intuitive yet powerful interface for editing subtitles</_li>
<_li>Support for many formats and character sets</_li>
<_li>Powerful video mode</_li>
<_li>Visual typesetting tools</_li>
<_li>Intuitive and customizable audio timing mode</_li>
<_li>Fully scriptable through the Automation module</_li>
</ul>
</description>
<launchable type="desktop-id">aegisub.desktop</launchable>
<kudos>
<kudo>HiDpiIcon</kudo>
<kudo>HighContrast</kudo>
<kudo>UserDocs</kudo>
</kudos>
<screenshots>
<screenshot type="default">
<_caption>Typesetting</_caption>
<image>http://static.aegisub.org/img/screenshots/unix/typesetting-efc51b7a.png</image>
</screenshot>
<screenshot>
<_caption>Audio video</_caption>
<image>http://static.aegisub.org/img/screenshots/unix/audio-video-f1f81fc2.png</image>
</screenshot>
<screenshot>
<_caption>Audio timing</_caption>
<image>http://static.aegisub.org/img/screenshots/unix/audio-timing-1d8fce7e.png</image>
</screenshot>
</screenshots>
<developer_name>Aegisub Group</developer_name>
<url type="bugtracker">https://github.com/Aegisub/Aegisub/issues</url>
<url type="faq">http://docs.aegisub.org/manual/FAQ</url>
<url type="help">http://docs.aegisub.org</url>
<url type="homepage">http://www.aegisub.org</url>
<url type="translate">https://sites.google.com/site/rockytdrontransifex/aegisub</url>
<content_rating type="oars-1.0">
<content_attribute id="social-info">mild</content_attribute>
</content_rating>
<translation type="gettext">aegisub</translation>
<provides>
<binary>aegisub</binary>
</provides>
<releases>
<release version="3.2.2" date="2014-12-08"/>
</releases>
</component>

View File

@ -1,10 +1,10 @@
[Desktop Entry]
Version=1.0
Type=Application
_Name=Aegisub
_GenericName=Subtitle Editor
_Comment=Create and edit subtitles for film and videos.
Exec=@AEGISUB_COMMAND@ %f
Name=Aegisub
GenericName=Subtitle Editor
Comment=Create and edit subtitles for film and videos.
Exec=env GDK_BACKEND=x11 @AEGISUB_COMMAND@ %f
TryExec=@AEGISUB_COMMAND@
Icon=aegisub
Terminal=false

View File

@ -64,6 +64,11 @@ Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedT
Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedTypes"; ValueType: string; ValueName: ".wav"; ValueData: ""; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedTypes"; ValueType: string; ValueName: ".ogg"; ValueData: ""; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedTypes"; ValueType: string; ValueName: ".avs"; ValueData: ""; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedTypes"; ValueType: string; ValueName: ".opus"; ValueData: ""; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedTypes"; ValueType: string; ValueName: ".h264"; ValueData: ""; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedTypes"; ValueType: string; ValueName: ".hevc"; ValueData: ""; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedTypes"; ValueType: string; ValueName: ".eac3"; ValueData: ""; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Classes\Applications\aegisub{#ARCH}.exe\SupportedTypes"; ValueType: string; ValueName: ".webm"; ValueData: ""; Flags: uninsdeletekey
; Class for general subtitle formats
Root: HKLM; Subkey: "SOFTWARE\Classes\Aegisub.Subtitle.1"; ValueType: string; ValueName: ""; ValueData: "Aegisub subtitle file"; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Classes\Aegisub.Subtitle.1"; ValueType: dword; ValueName: "EditFlags"; ValueData: $af0; Flags: uninsdeletekey
@ -195,4 +200,8 @@ Root: HKLM; Subkey: "SOFTWARE\Classes\.m4a\OpenWithProgids"; ValueType: string;
Root: HKLM; Subkey: "SOFTWARE\Classes\.wav\OpenWithProgids"; ValueType: string; ValueName: "Aegisub.Audio.1"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "SOFTWARE\Classes\.ogg\OpenWithProgids"; ValueType: string; ValueName: "Aegisub.Media.1"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "SOFTWARE\Classes\.avs\OpenWithProgids"; ValueType: string; ValueName: "Aegisub.Video.1"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "SOFTWARE\Classes\.opus\OpenWithProgids"; ValueType: string; ValueName: "Aegisub.Audio.1"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "SOFTWARE\Classes\.h264\OpenWithProgids"; ValueType: string; ValueName: "Aegisub.Video.1"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "SOFTWARE\Classes\.hevc\OpenWithProgids"; ValueType: string; ValueName: "Aegisub.Video.1"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "SOFTWARE\Classes\.eac3\OpenWithProgids"; ValueType: string; ValueName: "Aegisub.Audio.1"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "SOFTWARE\Classes\.webm\OpenWithProgids"; ValueType: string; ValueName: "Aegisub.Media.1"; Flags: uninsdeletevalue

View File

@ -46,6 +46,12 @@ do
| maybe_append
done
if which xmlstarlet >/dev/null 2>&1 && which jq >/dev/null 2>&1; then
for i in 'name' 'summary' 'p' 'li' 'caption'; do
xmlstarlet sel -t -v "//_$i" ../packages/desktop/aegisub.appdata.xml.template.in | jq -R .
done | nl -v0 -w1 -s'|' | sed -re 's/^/aegisub.appdata.xml|/' | maybe_append
fi
grep '^_[A-Za-z0-9]*=.*' ../packages/win_installer/fragment_strings.iss.in | while read line
do
echo "$line" \

View File

@ -66,6 +66,7 @@ src_OBJ := \
$(d)help_button.o \
$(d)hotkey.o \
$(d)hotkey_data_view_model.o \
$(d)image_position_picker.o \
$(d)initial_line_state.o \
$(d)main.o \
$(d)menu.o \
@ -188,14 +189,13 @@ endif
#####################
# SOURCE-LEVEL CFLAGS
#####################
$(d)MatroskaParser.o_FLAGS := -Wno-sometimes-uninitialized
$(d)audio_player.o_FLAGS := $(CFLAGS_ALSA) $(CFLAGS_PORTAUDIO) $(CFLAGS_LIBPULSE) $(CFLAGS_OPENAL)
$(d)audio_provider_factory.o_FLAGS := $(CFLAGS_FFMS2)
$(d)auto4_base.o_FLAGS := $(CFLAGS_FREETYPE)
$(d)charset_detect.o_FLAGS := -D_X86_
$(d)font_file_lister_fontconfig.o_FLAGS := $(CFLAGS_FONTCONFIG)
$(d)subtitles_provider.o_FLAGS := $(CFLAGS_LIBASS)
$(d)subtitles_provider_libass.o_FLAGS := $(CFLAGS_LIBASS) -Wno-c++11-narrowing
$(d)subtitles_provider_libass.o_FLAGS := $(CFLAGS_LIBASS) -Wno-narrowing
$(d)text_file_reader.o_FLAGS := -D_X86_
$(d)video_provider_manager.o_FLAGS := $(CFLAGS_FFMS2)
$(d)auto4_lua.o_FLAGS := $(CFLAGS_LUA)

View File

@ -48,7 +48,7 @@
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef _WIN32
#if !defined(_WIN32) && !defined(CMAKE_BUILD)
#include "../acconf.h"
#endif

View File

@ -41,7 +41,7 @@ class AssStyle final : public AssEntry, public AssEntryListHook {
public:
std::string name = "Default"; ///< Name of the style; must be case-insensitively unique within a file despite being case-sensitive
std::string font = "Arial"; ///< Font face name
double fontsize = 20.; ///< Font size
double fontsize = 48.; ///< Font size
agi::Color primary{ 255, 255, 255 }; ///< Default text color
agi::Color secondary{ 255, 0, 0 }; ///< Text color for not-yet-reached karaoke syllables

View File

@ -129,10 +129,9 @@ END_EVENT_TABLE()
void AudioBox::OnMouseWheel(wxMouseEvent &evt) {
if (!ForwardMouseWheelEvent(audioDisplay, evt))
return;
bool zoom = evt.CmdDown() != OPT_GET("Audio/Wheel Default to Zoom")->GetBool();
if (!zoom) {
int amount = -evt.GetWheelRotation() * GetClientSize().GetWidth() / (evt.GetWheelDelta() * 3);
int amount = -evt.GetWheelRotation();
// If the user did a horizontal scroll the amount should be inverted
// for it to be natural.
if (evt.GetWheelAxis() == 1) amount = -amount;

View File

@ -37,7 +37,7 @@
AudioColorScheme::AudioColorScheme(int prec, std::string const& scheme_name, int audio_rendering_style)
: palette((3<<prec) + 3)
, factor(1<<prec)
, factor((size_t)1<<prec)
{
std::string opt_base = "Colour/Schemes/" + scheme_name + "/";
switch (static_cast<AudioRenderingStyle>(audio_rendering_style))

View File

@ -128,8 +128,9 @@ public:
/// Get the current Selection colour
wxColour Selection() const { return focused ? sel_focused_colour : sel_colour; }
};
}
class AudioDisplayScrollbar final : public AudioDisplayInteractionObject {
class AudioDisplay::AudioDisplayScrollbar final : public AudioDisplayInteractionObject {
static const int height = 15;
static const int min_width = 10;
@ -267,9 +268,9 @@ public:
}
};
const int AudioDisplayScrollbar::min_width;
const int AudioDisplay::AudioDisplayScrollbar::min_width;
class AudioDisplayTimeline final : public AudioDisplayInteractionObject {
class AudioDisplay::AudioDisplayTimeline final : public AudioDisplayInteractionObject {
int duration = 0; ///< Total duration in ms
double ms_per_pixel = 1.0; ///< Milliseconds per pixel
int pixel_left = 0; ///< Leftmost visible pixel (i.e. scroll position)
@ -478,6 +479,7 @@ public:
}
};
namespace {
class AudioStyleRangeMerger final : public AudioRenderingStyleRanges {
typedef std::map<int, AudioRenderingStyle> style_map;
public:

View File

@ -47,11 +47,6 @@ class AudioRenderer;
class AudioRendererBitmapProvider;
class TimeRange;
// Helper classes used in implementation of the audio display
namespace {
class AudioDisplayScrollbar;
class AudioDisplayTimeline;
}
class AudioDisplayInteractionObject;
class AudioMarkerInteractionObject;
@ -79,9 +74,11 @@ class AudioDisplay: public wxWindow {
agi::AudioProvider *provider = nullptr;
/// Scrollbar helper object
class AudioDisplayScrollbar;
std::unique_ptr<AudioDisplayScrollbar> scrollbar;
/// Timeline helper object
class AudioDisplayTimeline;
std::unique_ptr<AudioDisplayTimeline> timeline;
/// The interaction object for the last-dragged audio marker

View File

@ -280,8 +280,7 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
split_area->Refresh(false);
scroll_timer.Start(50);
split_area->CaptureMouse();
wxTimerEvent evt;
OnScrollTimer(evt);
OnScrollTimer();
}
return;
}
@ -317,7 +316,7 @@ void AudioKaraoke::OnMouse(wxMouseEvent &event) {
split_area->Refresh(false);
}
void AudioKaraoke::OnScrollTimer(wxTimerEvent &) {
void AudioKaraoke::OnScrollTimer() {
scroll_x += scroll_dir * char_width * 3;
int max_scroll = rendered_line.GetWidth() + 20 - split_area->GetClientSize().GetWidth();
@ -329,6 +328,10 @@ void AudioKaraoke::OnScrollTimer(wxTimerEvent &) {
split_area->Refresh(false);
}
void AudioKaraoke::OnScrollTimer(wxTimerEvent&) {
OnScrollTimer();
}
void AudioKaraoke::LoadFromLine() {
scroll_x = 0;
scroll_timer.Stop();

View File

@ -142,7 +142,8 @@ class AudioKaraoke final : public wxWindow {
void OnPaint(wxPaintEvent &event);
void OnSize(wxSizeEvent &event);
void OnAudioOpened(agi::AudioProvider *provider);
void OnScrollTimer(wxTimerEvent &event);
void OnScrollTimer();
void OnScrollTimer(wxTimerEvent& event);
public:
/// Constructor

View File

@ -40,13 +40,25 @@
#include <boost/range/iterator_range.hpp>
#ifdef WITH_ALSA
std::unique_ptr<AudioPlayer> CreateAlsaPlayer(agi::AudioProvider *providers, wxWindow *window);
#endif
#ifdef WITH_DIRECTSOUND
std::unique_ptr<AudioPlayer> CreateDirectSoundPlayer(agi::AudioProvider *providers, wxWindow *window);
std::unique_ptr<AudioPlayer> CreateDirectSound2Player(agi::AudioProvider *providers, wxWindow *window);
#endif
#ifdef WITH_OPENAL
std::unique_ptr<AudioPlayer> CreateOpenALPlayer(agi::AudioProvider *providers, wxWindow *window);
#endif
#ifdef WITH_PORTAUDIO
std::unique_ptr<AudioPlayer> CreatePortAudioPlayer(agi::AudioProvider *providers, wxWindow *window);
#endif
#ifdef WITH_LIBPULSE
std::unique_ptr<AudioPlayer> CreatePulseAudioPlayer(agi::AudioProvider *providers, wxWindow *window);
#endif
#ifdef WITH_OSS
std::unique_ptr<AudioPlayer> CreateOSSPlayer(agi::AudioProvider *providers, wxWindow *window);
#endif
namespace {
struct factory {

View File

@ -45,6 +45,7 @@
#include <mmsystem.h>
#include <dsound.h>
#include <cguid.h>
namespace {
class DirectSoundPlayer;

View File

@ -48,6 +48,7 @@
#include <mmsystem.h>
#include <process.h>
#include <dsound.h>
#include <cguid.h>
namespace {
class DirectSoundPlayer2Thread;

View File

@ -144,7 +144,7 @@ void FFmpegSourceAudioProvider::LoadAudio(agi::fs::path const& filename) {
// update access time of index file so it won't get cleaned away
agi::fs::Touch(CacheName);
AudioSource = FFMS_CreateAudioSource(filename.string().c_str(), TrackNumber, Index, -1, &ErrInfo);
AudioSource = FFMS_CreateAudioSource(filename.string().c_str(), TrackNumber, Index, FFMS_DELAY_FIRST_VIDEO_TRACK, &ErrInfo);
if (!AudioSource)
throw agi::AudioProviderError(std::string("Failed to open audio track: ") + ErrInfo.Buffer);

View File

@ -114,7 +114,7 @@ void AudioSpectrumRenderer::RecreateCache()
if (provider)
{
size_t block_count = (size_t)((provider->GetNumSamples() + (size_t)(1<<derivation_dist) - 1) >> derivation_dist);
size_t block_count = (size_t)((provider->GetNumSamples() + ((size_t)1<<derivation_dist) - 1) >> derivation_dist);
cache = agi::make_unique<AudioSpectrumCache>(block_count, this);
#ifdef WITH_FFTW3
@ -170,7 +170,7 @@ void AudioSpectrumRenderer::FillBlock(size_t block_index, float *block)
assert(cache);
assert(block);
int64_t first_sample = ((int64_t)block_index) << derivation_dist;
int64_t first_sample = (((int64_t)block_index) << derivation_dist) - ((int64_t)1 << derivation_size);
provider->GetAudio(&audio_scratch[0], first_sample, 2 << derivation_size);
#ifdef WITH_FFTW3
@ -181,7 +181,7 @@ void AudioSpectrumRenderer::FillBlock(size_t block_index, float *block)
double scale_factor = 9 / sqrt(2 << (derivation_size + 1));
fftw_complex *o = dft_output;
for (size_t si = 1<<derivation_size; si > 0; --si)
for (size_t si = (size_t)1<<derivation_size; si > 0; --si)
{
*block++ = log10( sqrt(o[0][0] * o[0][0] + o[0][1] * o[0][1]) * scale_factor + 1 );
o++;

View File

@ -390,7 +390,7 @@ int AudioTimingControllerKaraoke::MoveMarker(KaraokeMarker *marker, int new_posi
void AudioTimingControllerKaraoke::AnnounceChanges(int syl) {
if (syl < 0) return;
if (syl == cur_syl || syl == cur_syl + 1) {
if (static_cast<unsigned>(syl) == cur_syl || static_cast<unsigned>(syl) == cur_syl + 1) {
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
}

View File

@ -44,6 +44,7 @@
#include "audio_timing.h"
#include "command/command.h"
#include "compat.h"
#include "frame_main.h"
#include "include/aegisub/context.h"
#include "options.h"
#include "project.h"
@ -52,6 +53,7 @@
#include "video_controller.h"
#include "utils.h"
#include <libaegisub/dispatch.h>
#include <libaegisub/format.h>
#include <libaegisub/lua/ffi.h>
#include <libaegisub/lua/modules.h>
@ -270,6 +272,19 @@ namespace {
return 2;
}
int lua_set_status_text(lua_State *L)
{
const agi::Context *c = get_context(L);
if (!c || !c->frame) {
lua_pushnil(L);
return 1;
}
std::string text = check_string(L, 1);
lua_pop(L, 1);
agi::dispatch::Main().Async([=] { c->frame->StatusTimeout(to_wx(text)); });
return 0;
}
int project_properties(lua_State *L)
{
const agi::Context *c = get_context(L);
@ -473,6 +488,7 @@ namespace {
set_field<get_translation>(L, "gettext");
set_field<project_properties>(L, "project_properties");
set_field<lua_get_audio_selection>(L, "get_audio_selection");
set_field<lua_set_status_text>(L, "set_status_text");
// store aegisub table to globals
lua_settable(L, LUA_GLOBALSINDEX);

View File

@ -744,8 +744,8 @@ namespace Automation4 {
, can_modify(can_modify)
, can_set_undo(can_set_undo)
{
for (auto& line : ass->Info)
lines.push_back(nullptr);
// for (auto& line : ass->Info) lines.push_back(nullptr);
lines.insert(lines.end(), ass->Info.size(), nullptr);
for (auto& line : ass->Styles)
lines.push_back(&line);
for (auto& line : ass->Events)

View File

@ -1,751 +0,0 @@
// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al.
// http://www.avisynth.org
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
// http://www.gnu.org/copyleft/gpl.html .
//
// Linking Avisynth statically or dynamically with other modules is making a
// combined work based on Avisynth. Thus, the terms and conditions of the GNU
// General Public License cover the whole combination.
//
// As a special exception, the copyright holders of Avisynth give you
// permission to link Avisynth with independent modules that communicate with
// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
// terms of these independent modules, and to copy and distribute the
// resulting combined work under terms of your choice, provided that
// every copy of the combined work is accompanied by a complete copy of
// the source code of Avisynth (the version of Avisynth used to produce the
// combined work), being distributed under the terms of the GNU General
// Public License plus this exception. An independent module is a module
// which is not derived from or based on Avisynth, such as 3rd-party filters,
// import and export plugins, or graphical user interfaces.
#ifndef __AVISYNTH_H__
#define __AVISYNTH_H__
enum { AVISYNTH_INTERFACE_VERSION = 3 };
/* Define all types necessary for interfacing with avisynth.dll
Moved from internal.h */
// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc.
#include <windef.h>
// COM interface macros
#include <objbase.h>
// Raster types used by VirtualDub & Avisynth
#define in64 (__int64)(unsigned short)
typedef unsigned long Pixel; // this will break on 64-bit machines!
typedef unsigned long Pixel32;
typedef unsigned char Pixel8;
typedef long PixCoord;
typedef long PixDim;
typedef long PixOffset;
/* Compiler-specific crap */
// Tell MSVC to stop precompiling here
#ifdef _MSC_VER
#pragma hdrstop
#endif
// Set up debugging macros for MS compilers; for others, step down to the
// standard <assert.h> interface
#ifdef _MSC_VER
#include <crtdbg.h>
#else
#define _RPT0(a,b) ((void)0)
#define _RPT1(a,b,c) ((void)0)
#define _RPT2(a,b,c,d) ((void)0)
#define _RPT3(a,b,c,d,e) ((void)0)
#define _RPT4(a,b,c,d,e,f) ((void)0)
#define _ASSERTE(x) assert(x)
#include <assert.h>
#endif
// I had problems with Premiere wanting 1-byte alignment for its structures,
// so I now set the Avisynth struct alignment explicitly here.
#pragma pack(push,8)
#define FRAME_ALIGN 16
// Default frame alignment is 16 bytes, to help P4, when using SSE2
// The VideoInfo struct holds global information about a clip (i.e.
// information that does not depend on the frame number). The GetVideoInfo
// method in IClip returns this struct.
// Audio Sample information
typedef float SFLOAT;
enum {SAMPLE_INT8 = 1<<0,
SAMPLE_INT16 = 1<<1,
SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware.
SAMPLE_INT32 = 1<<3,
SAMPLE_FLOAT = 1<<4};
enum {
PLANAR_Y=1<<0,
PLANAR_U=1<<1,
PLANAR_V=1<<2,
PLANAR_ALIGNED=1<<3,
PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED,
PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED,
PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED,
};
struct VideoInfo {
int width, height; // width=0 means no video
unsigned fps_numerator, fps_denominator;
int num_frames;
// This is more extensible than previous versions. More properties can be added seeminglesly.
// Colorspace properties.
enum {
CS_BGR = 1<<28,
CS_YUV = 1<<29,
CS_INTERLEAVED = 1<<30,
CS_PLANAR = 1<<31
};
// Specific colorformats
enum { CS_UNKNOWN = 0,
CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED,
CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED,
CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED,
CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, planar
CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, planar
CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above
};
int pixel_type; // changed to int as of 2.5
int audio_samples_per_second; // 0 means no audio
int sample_type; // as of 2.5
__int64 num_audio_samples; // changed as of 2.5
int nchannels; // as of 2.5
// Imagetype properties
int image_type;
enum {
IT_BFF = 1<<0,
IT_TFF = 1<<1,
IT_FIELDBASED = 1<<2
};
// useful functions of the above
bool HasVideo() const { return (width!=0); }
bool HasAudio() const { return (audio_samples_per_second!=0); }
bool IsRGB() const { return !!(pixel_type&CS_BGR); }
bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties
bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; }
bool IsYUV() const { return !!(pixel_type&CS_YUV ); }
bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; }
bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); }
bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); }
bool Is(int property) const { return ((pixel_type & property)==property ); }
bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); }
bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); }
bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); }
bool IsBFF() const { return !!(image_type & IT_BFF); }
bool IsTFF() const { return !!(image_type & IT_TFF); }
bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this
int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes
int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images
int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); }
__int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; }
int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; }
__int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; }
__int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); }
int AudioChannels() const { return nchannels; }
int SampleType() const{ return sample_type;}
bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);}
int SamplesPerSecond() const { return audio_samples_per_second; }
int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();}
void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; }
void Set(int property) { image_type|=property; }
void Clear(int property) { image_type&=~property; }
int BitsPerPixel() const {
switch (pixel_type) {
case CS_BGR24:
return 24;
case CS_BGR32:
return 32;
case CS_YUY2:
return 16;
case CS_YV12:
case CS_I420:
return 12;
default:
return 0;
}
}
int BytesPerChannelSample() const {
switch (sample_type) {
case SAMPLE_INT8:
return sizeof(signed char);
case SAMPLE_INT16:
return sizeof(signed short);
case SAMPLE_INT24:
return 3;
case SAMPLE_INT32:
return sizeof(signed int);
case SAMPLE_FLOAT:
return sizeof(SFLOAT);
default:
_ASSERTE("Sample type not recognized!");
return 0;
}
}
// useful mutator
void SetFPS(unsigned numerator, unsigned denominator) {
if ((numerator == 0) || (denominator == 0)) {
fps_numerator = 0;
fps_denominator = 1;
}
else {
unsigned x=numerator, y=denominator;
while (y) { // find gcd
unsigned t = x%y; x = y; y = t;
}
fps_numerator = numerator/x;
fps_denominator = denominator/x;
}
}
// Range protected multiply-divide of FPS
void MulDivFPS(unsigned multiplier, unsigned divisor) {
unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier);
unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor);
unsigned __int64 x=numerator, y=denominator;
while (y) { // find gcd
unsigned __int64 t = x%y; x = y; y = t;
}
numerator /= x; // normalize
denominator /= x;
unsigned __int64 temp = numerator | denominator; // Just looking top bit
unsigned u = 0;
while (temp & 0xffffffff80000000) { // or perhaps > 16777216*2
temp = Int64ShrlMod32(temp, 1);
u++;
}
if (u) { // Scale to fit
const unsigned round = 1 << (u-1);
SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u),
(unsigned)Int64ShrlMod32(denominator + round, u) );
}
else {
fps_numerator = (unsigned)numerator;
fps_denominator = (unsigned)denominator;
}
}
// Test for same colorspace
bool IsSameColorspace(const VideoInfo& vi) const {
if (vi.pixel_type == pixel_type) return TRUE;
if (IsYV12() && vi.IsYV12()) return TRUE;
return FALSE;
}
};
// VideoFrameBuffer holds information about a memory block which is used
// for video data. For efficiency, instances of this class are not deleted
// when the refcount reaches zero; instead they're stored in a linked list
// to be reused. The instances are deleted when the corresponding AVS
// file is closed.
class VideoFrameBuffer {
BYTE* const data;
const int data_size;
// sequence_number is incremented every time the buffer is changed, so
// that stale views can tell they're no longer valid.
long sequence_number;
friend class VideoFrame;
friend class Cache;
friend class ScriptEnvironment;
long refcount;
public:
VideoFrameBuffer(int size);
VideoFrameBuffer();
~VideoFrameBuffer();
const BYTE* GetReadPtr() const { return data; }
BYTE* GetWritePtr() { ++sequence_number; return data; }
int GetDataSize() { return data_size; }
int GetSequenceNumber() { return sequence_number; }
int GetRefcount() { return refcount; }
};
class IClip;
class PClip;
class PVideoFrame;
class IScriptEnvironment;
class AVSValue;
// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new
// is overloaded to recycle class instances.
class VideoFrame {
int refcount;
VideoFrameBuffer* const vfb;
const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture.
friend class PVideoFrame;
void AddRef() { InterlockedIncrement((long *)&refcount); }
void Release() { if (refcount==1) InterlockedDecrement(&vfb->refcount); InterlockedDecrement((long *)&refcount); }
friend class ScriptEnvironment;
friend class Cache;
VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height);
VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV);
void* operator new(size_t size);
// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard!
public:
int GetPitch() const { return pitch; }
int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; }
int GetRowSize() const { return row_size; }
int GetRowSize(int plane) const {
switch (plane) {
case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0;
case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED:
if (pitchUV) {
int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize
if (r<=pitchUV)
return r;
return row_size>>1;
} else return 0;
case PLANAR_Y_ALIGNED:
int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize
if (r<=pitch)
return r;
return row_size;
}
return row_size; }
int GetHeight() const { return height; }
int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; }
// generally you shouldn't use these three
VideoFrameBuffer* GetFrameBuffer() const { return vfb; }
int GetOffset() const { return offset; }
int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; }
// in plugins use env->SubFrame()
VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const;
VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const;
const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; }
const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); }
bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); }
BYTE* GetWritePtr() const {
if (vfb->GetRefcount()>1) {
_ASSERT(FALSE);
//throw AvisynthError("Internal Error - refcount was more than one!");
}
return IsWritable() ? (vfb->GetWritePtr() + offset) : 0;
}
BYTE* GetWritePtr(int plane) const {
if (plane==PLANAR_Y) {
if (vfb->GetRefcount()>1) {
_ASSERT(FALSE);
// throw AvisynthError("Internal Error - refcount was more than one!");
}
return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0;
}
return vfb->data + GetOffset(plane);
}
~VideoFrame() { InterlockedDecrement(&vfb->refcount); }
};
enum {
CACHE_NOTHING=0,
CACHE_RANGE=1,
CACHE_ALL=2,
CACHE_AUDIO=3,
CACHE_AUDIO_NONE=4
};
// Base class for all filters.
class IClip {
friend class PClip;
friend class AVSValue;
int refcnt;
void AddRef() { InterlockedIncrement((long *)&refcnt); }
void Release() { InterlockedDecrement((long *)&refcnt); if (!refcnt) delete this; }
public:
IClip() : refcnt(0) {}
virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; }
virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0;
virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame
virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples
virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter.
virtual const VideoInfo& __stdcall GetVideoInfo() = 0;
virtual __stdcall ~IClip() {}
};
// smart pointer to IClip
class PClip {
IClip* p;
IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; }
friend class AVSValue;
friend class VideoFrame;
void Init(IClip* x) {
if (x) x->AddRef();
p=x;
}
void Set(IClip* x) {
if (x) x->AddRef();
if (p) p->Release();
p=x;
}
public:
PClip() { p = 0; }
PClip(const PClip& x) { Init(x.p); }
PClip(IClip* x) { Init(x); }
void operator=(IClip* x) { Set(x); }
void operator=(const PClip& x) { Set(x.p); }
IClip* operator->() const { return p; }
// useful in conditional expressions
operator void*() const { return p; }
bool operator!() const { return !p; }
~PClip() { if (p) p->Release(); }
};
// smart pointer to VideoFrame
class PVideoFrame {
VideoFrame* p;
void Init(VideoFrame* x) {
if (x) x->AddRef();
p=x;
}
void Set(VideoFrame* x) {
if (x) x->AddRef();
if (p) p->Release();
p=x;
}
public:
PVideoFrame() { p = 0; }
PVideoFrame(const PVideoFrame& x) { Init(x.p); }
PVideoFrame(VideoFrame* x) { Init(x); }
void operator=(VideoFrame* x) { Set(x); }
void operator=(const PVideoFrame& x) { Set(x.p); }
VideoFrame* operator->() const { return p; }
// for conditional expressions
operator void*() const { return p; }
bool operator!() const { return !p; }
~PVideoFrame() { if (p) p->Release();}
};
class AVSValue {
public:
AVSValue() { type = 'v'; }
AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); }
AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); }
AVSValue(bool b) { type = 'b'; boolean = b; }
AVSValue(int i) { type = 'i'; integer = i; }
// AVSValue(__int64 l) { type = 'l'; longlong = l; }
AVSValue(float f) { type = 'f'; floating_pt = f; }
AVSValue(double f) { type = 'f'; floating_pt = float(f); }
AVSValue(const char* s) { type = 's'; string = s; }
AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; }
AVSValue(const AVSValue& v) { Assign(&v, true); }
~AVSValue() { if (IsClip() && clip) clip->Release(); }
AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; }
// Note that we transparently allow 'int' to be treated as 'float'.
// There are no int<->bool conversions, though.
bool Defined() const { return type != 'v'; }
bool IsClip() const { return type == 'c'; }
bool IsBool() const { return type == 'b'; }
bool IsInt() const { return type == 'i'; }
// bool IsLong() const { return (type == 'l'|| type == 'i'); }
bool IsFloat() const { return type == 'f' || type == 'i'; }
bool IsString() const { return type == 's'; }
bool IsArray() const { return type == 'a'; }
PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; }
bool AsBool() const { _ASSERTE(IsBool()); return boolean; }
int AsInt() const { _ASSERTE(IsInt()); return integer; }
// int AsLong() const { _ASSERTE(IsLong()); return longlong; }
const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; }
double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; }
bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; }
int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; }
double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; }
const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; }
int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; }
const AVSValue& operator[](int index) const {
_ASSERTE(IsArray() && index>=0 && index<array_size);
return (IsArray() && index>=0 && index<array_size) ? array[index] : *this;
}
private:
short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong
short array_size;
union {
IClip* clip;
bool boolean;
int integer;
float floating_pt;
const char* string;
const AVSValue* array;
// __int64 longlong;
};
void Assign(const AVSValue* src, bool init) {
if (src->IsClip() && src->clip)
src->clip->AddRef();
if (!init && IsClip() && clip)
clip->Release();
// make sure this copies the whole struct!
//((__int32*)this)[0] = ((__int32*)src)[0];
//((__int32*)this)[1] = ((__int32*)src)[1];
memcpy(this, src, sizeof(AVSValue));
}
};
// instantiable null filter
class GenericVideoFilter : public IClip {
protected:
PClip child;
VideoInfo vi;
public:
GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); }
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); }
void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); }
const VideoInfo& __stdcall GetVideoInfo() { return vi; }
bool __stdcall GetParity(int n) { return child->GetParity(n); }
void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter.
};
class AvisynthError /* exception */ {
public:
const char* const msg;
AvisynthError(const char* _msg) : msg(_msg) {}
};
/* Helper classes useful to plugin authors */
class AlignPlanar : public GenericVideoFilter
{
public:
AlignPlanar(PClip _clip);
static PClip Create(PClip clip);
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};
class FillBorder : public GenericVideoFilter
{
public:
FillBorder(PClip _clip);
static PClip Create(PClip clip);
PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
};
class ConvertAudio : public GenericVideoFilter
/**
* Helper class to convert audio to any format
**/
{
public:
ConvertAudio(PClip _clip, int prefered_format);
void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env);
void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache!
static PClip Create(PClip clip, int sample_type, int prefered_type);
static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*);
static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*);
static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*);
static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*);
static AVSValue __cdecl Create_8bit(AVSValue args, void*, IScriptEnvironment*);
virtual ~ConvertAudio();
private:
void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count);
void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count);
void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count);
void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count);
void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count);
void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count);
void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count);
void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count);
__inline int Saturate_int8(float n);
__inline short Saturate_int16(float n);
__inline int Saturate_int24(float n);
__inline int Saturate_int32(float n);
char src_format;
char dst_format;
int src_bps;
char *tempbuffer;
SFLOAT *floatbuffer;
int tempbuffer_size;
};
// For GetCPUFlags. These are backwards-compatible with those in VirtualDub.
enum {
/* slowest CPU to support extension */
CPUF_FORCE = 0x01, // N/A
CPUF_FPU = 0x02, // 386/486DX
CPUF_MMX = 0x04, // P55C, K6, PII
CPUF_INTEGER_SSE = 0x08, // PIII, Athlon
CPUF_SSE = 0x10, // PIII, Athlon XP/MP
CPUF_SSE2 = 0x20, // PIV, Hammer
CPUF_3DNOW = 0x40, // K6-2
CPUF_3DNOW_EXT = 0x80, // Athlon
CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which only Hammer
// will have anyway)
CPUF_SSE3 = 0x100, // Some P4 & Athlon 64.
};
#define MAX_INT 0x7fffffff
#define MIN_INT -0x7fffffff
class IScriptEnvironment {
public:
virtual __stdcall ~IScriptEnvironment() {}
virtual /*static*/ long __stdcall GetCPUFlags() = 0;
virtual char* __stdcall SaveString(const char* s, int length = -1) = 0;
virtual char* __stdcall Sprintf(const char* fmt, ...) = 0;
// note: val is really a va_list; I hope everyone typedefs va_list to a pointer
virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0;
__declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0;
class NotFound /*exception*/ {}; // thrown by Invoke and GetVar
typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env);
virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0;
virtual bool __stdcall FunctionExists(const char* name) = 0;
virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0;
virtual AVSValue __stdcall GetVar(const char* name) = 0;
virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0;
virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0;
virtual void __stdcall PushContext(int level=0) = 0;
virtual void __stdcall PopContext() = 0;
// align should be 4 or 8
virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0;
virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0;
virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0;
typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env);
virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0;
virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0;
virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0;
virtual int __stdcall SetMemoryMax(int mem) = 0;
virtual int __stdcall SetWorkingDir(const char * newdir) = 0;
virtual void* __stdcall ManageCache(int key, void* data) = 0;
enum PlanarChromaAlignmentMode {
PlanarChromaAlignmentOff,
PlanarChromaAlignmentOn,
PlanarChromaAlignmentTest };
virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0;
virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0;
};
// avisynth.dll exports this; it's a way to use it as a library, without
// writing an AVS script or without going through AVIFile.
IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION);
#pragma pack(pop)
#endif //__AVISYNTH_H__

View File

@ -35,7 +35,7 @@
#ifdef WITH_AVISYNTH
#include "avisynth_wrap.h"
#include "avisynth.h"
#include <avisynth.h>
#include "options.h"
#include <mutex>

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

View File

@ -51,6 +51,11 @@ button/bugtracker_button_24.png
button/bugtracker_button_32.png
button/bugtracker_button_48.png
button/bugtracker_button_64.png
button/button_align_16.png
button/button_align_24.png
button/button_align_32.png
button/button_align_48.png
button/button_align_64.png
button/button_audio_commit_16.png
button/button_audio_commit_24.png
button/button_audio_commit_32.png

View File

@ -150,8 +150,11 @@ public:
}
// Remove old entries until we're under the max size
for (auto it = age.rbegin(); size > max_size && it != age.rend(); )
KillMacroBlock(**it++);
while (size > max_size) {
// When size > 0, age should never be empty
assert(!age.empty());
KillMacroBlock(*age.back());
}
}
/// @brief Obtain a data block from the cache

View File

@ -18,9 +18,13 @@
#include "dialogs.h"
#if BOOST_VERSION >= 106900
#include <boost/gil.hpp>
#else
#include <boost/gil/gil_all.hpp>
#endif
AGI_DEFINE_EVENT(EVT_COLOR, agi::Color);
AGI_DEFINE_EVENT(EVT_COLOR, agi::Color)
ColourButton::ColourButton(wxWindow *parent, wxSize const& size, bool alpha, agi::Color col, wxValidator const& validator)
: wxButton(parent, -1, "", wxDefaultPosition, wxSize(size.GetWidth() + 6, size.GetHeight() + 6), 0, validator)

View File

@ -22,7 +22,7 @@
/// Emitted by ColourButton when the user picks a new color, with the chosen
/// color set to the event payload
AGI_DECLARE_EVENT(EVT_COLOR, agi::Color);
AGI_DECLARE_EVENT(EVT_COLOR, agi::Color)
/// A button which displays a currently-selected color and lets the user pick
/// a new color when clicked
@ -43,6 +43,12 @@ public:
/// Get the currently selected color
agi::Color GetColor() { return colour; }
void SetColor(agi::Color color)
{
colour = color;
UpdateBitmap();
}
};
struct ColorValidator final : public wxValidator {

View File

@ -80,7 +80,7 @@ struct audio_open final : public Command {
STR_HELP("Open an audio file")
void operator()(agi::Context *c) override {
auto str = from_wx(_("Audio Formats") + " (*.aac,*.ac3,*.ape,*.dts,*.flac,*.m4a,*.mka,*.mp3,*.mp4,*.ogg,*.w64,*.wav,*.wma)|*.aac;*.ac3;*.ape;*.dts;*.flac;*.m4a;*.mka;*.mp3;*.mp4;*.ogg;*.w64;*.wav;*.wma|"
auto str = from_wx(_("Audio Formats") + " (*.aac,*.ac3,*.ape,*.dts,*.eac3,*.flac,*.m4a,*.mka,*.mp3,*.mp4,*.ogg,*.opus,*.w64,*.wav,*.wma)|*.aac;*.ac3;*.ape;*.dts;*.eac3;*.flac;*.m4a;*.mka;*.mp3;*.mp4;*.ogg;*.opus;*.w64;*.wav;*.wma|"
+ _("Video Formats") + " (*.asf,*.avi,*.avs,*.d2v,*.m2ts,*.m4v,*.mkv,*.mov,*.mp4,*.mpeg,*.mpg,*.ogm,*.webm,*.wmv,*.ts)|*.asf;*.avi;*.avs;*.d2v;*.m2ts;*.m4v;*.mkv;*.mov;*.mp4;*.mpeg;*.mpg;*.ogm;*.webm;*.wmv;*.ts|"
+ _("All Files") + " (*.*)|*.*");
auto filename = OpenFileSelector(_("Open Audio File"), "Path/Last/Audio", "", "", str, c->parent);

View File

@ -35,10 +35,10 @@ namespace agi { struct Context; }
#define CMD_TYPE(a) int Type() const override { using namespace cmd; return a; }
#define CMD_ICON(icon) wxBitmap Icon(int size, wxLayoutDirection dir = wxLayout_LeftToRight) const override { \
if (size == 64) return GETIMAGEDIR(icon##_64, dir); \
if (size == 48) return GETIMAGEDIR(icon##_48, dir); \
if (size == 32) return GETIMAGEDIR(icon##_32, dir); \
if (size == 24) return GETIMAGEDIR(icon##_24, dir); \
if (size >= 64) return GETIMAGEDIR(icon##_64, dir); \
if (size >= 48) return GETIMAGEDIR(icon##_48, dir); \
if (size >= 32) return GETIMAGEDIR(icon##_32, dir); \
if (size >= 24) return GETIMAGEDIR(icon##_24, dir); \
return GETIMAGEDIR(icon##_16, dir); \
}

View File

@ -672,7 +672,7 @@ static void duplicate_lines(agi::Context *c, int shift) {
// after the selected block
do {
auto old_diag = &*start;
auto new_diag = new AssDialogue(*old_diag);
auto new_diag = new AssDialogue(*old_diag);
c->ass->Events.insert(insert_pos, *new_diag);
new_sel.insert(new_diag);
@ -697,8 +697,8 @@ static void duplicate_lines(agi::Context *c, int shift) {
new_diag->Start = c->videoController->TimeAtFrame(cur_frame, agi::vfr::START);
}
else {
old_diag->Start = c->videoController->TimeAtFrame(cur_frame + 1, agi::vfr::START);
new_diag->End = c->videoController->TimeAtFrame(cur_frame, agi::vfr::END);
old_diag->End = c->videoController->TimeAtFrame(cur_frame, agi::vfr::END);
new_diag->Start = c->videoController->TimeAtFrame(cur_frame + 1, agi::vfr::START);
}
/// @todo also split \t and \move?

View File

@ -59,7 +59,7 @@ struct help_bugs final : public Command {
throw c->parent;
}
}
wxLaunchDefaultBrowser("http://devel.aegisub.org/", wxBROWSER_NEW_WINDOW);
wxLaunchDefaultBrowser("https://github.com/Aegisub/Aegisub/issues", wxBROWSER_NEW_WINDOW);
}
};
@ -75,18 +75,6 @@ struct help_contents final : public Command {
}
};
struct help_forums final : public Command {
CMD_NAME("help/forums")
CMD_ICON(forums_button)
STR_MENU("&Forums")
STR_DISP("Forums")
STR_HELP("Visit Aegisub's forums")
void operator()(agi::Context *) override {
wxLaunchDefaultBrowser("http://forum.aegisub.org/", wxBROWSER_NEW_WINDOW);
}
};
struct help_irc final : public Command {
CMD_NAME("help/irc")
CMD_ICON(irc_button)
@ -128,7 +116,6 @@ namespace cmd {
void init_help() {
reg(agi::make_unique<help_bugs>());
reg(agi::make_unique<help_contents>());
reg(agi::make_unique<help_forums>());
reg(agi::make_unique<help_irc>());
reg(agi::make_unique<help_video>());
reg(agi::make_unique<help_website>());

View File

@ -235,6 +235,18 @@ struct time_snap_scene final : public validate_video_loaded {
}
};
struct time_align_subtitle_to_point final : public validate_video_loaded {
CMD_NAME("time/align")
CMD_ICON(button_align)
STR_MENU("Align subtitle to video")
STR_DISP("Align subtitle to video")
STR_HELP("Align subtitle to video by key points")
void operator()(agi::Context* c) override {
c->videoController->Stop();
ShowAlignToVideoDialog(c);
}
};
struct time_add_lead_both final : public Command {
CMD_NAME("time/lead/both")
STR_MENU("Add lead in and out")
@ -393,6 +405,7 @@ namespace cmd {
reg(agi::make_unique<time_snap_end_video>());
reg(agi::make_unique<time_snap_scene>());
reg(agi::make_unique<time_snap_start_video>());
reg(agi::make_unique<time_align_subtitle_to_point>());
reg(agi::make_unique<time_start_decrease>());
reg(agi::make_unique<time_start_increase>());
}

View File

@ -564,7 +564,7 @@ struct video_open final : public Command {
STR_HELP("Open a video file")
void operator()(agi::Context *c) override {
auto str = from_wx(_("Video Formats") + " (*.asf,*.avi,*.avs,*.d2v,*.m2ts,*.m4v,*.mkv,*.mov,*.mp4,*.mpeg,*.mpg,*.ogm,*.webm,*.wmv,*.ts,*.y4m,*.yuv)|*.asf;*.avi;*.avs;*.d2v;*.m2ts;*.m4v;*.mkv;*.mov;*.mp4;*.mpeg;*.mpg;*.ogm;*.webm;*.wmv;*.ts;*.y4m;*.yuv|"
auto str = from_wx(_("Video Formats") + " (*.asf,*.avi,*.avs,*.d2v,*.h264,*.hevc,*.m2ts,*.m4v,*.mkv,*.mov,*.mp4,*.mpeg,*.mpg,*.ogm,*.webm,*.wmv,*.ts,*.y4m,*.yuv)|*.asf;*.avi;*.avs;*.d2v;*.h264;*.hevc;*.m2ts;*.m4v;*.mkv;*.mov;*.mp4;*.mpeg;*.mpg;*.ogm;*.webm;*.wmv;*.ts;*.y4m;*.yuv|"
+ _("All Files") + " (*.*)|*.*");
auto filename = OpenFileSelector(_("Open video file"), "Path/Last/Video", "", "", str, c->parent);
if (!filename.empty())

View File

@ -49,10 +49,11 @@ void ShowAboutDialog(wxWindow *parent) {
// Generate about string
wxString aboutString = wxString("Aegisub ") + GetAegisubShortVersionString() + ".\n"
"Copyright (c) 2005-2014 Rodrigo Braz Monteiro, Niels Martin Hansen, Thomas Goyne et al.\n\n"
"Copyright (c) 2005-2019 Rodrigo Braz Monteiro, Niels Martin Hansen, Thomas Goyne et al.\n\n"
"Programmers:\n"
" Alysson Souza e Silva\n"
" Amar Takhar\n"
" Charlie Jiang\n"
" Dan Donovan\n"
" Daniel Moscoviter\n"
" David Conrad\n"
@ -67,6 +68,7 @@ void ShowAboutDialog(wxWindow *parent) {
" Muhammad Lukman Nasaruddin\n"
" Niels Martin Hansen\n"
" Patryk Pomykalski\n"
" Qirui Wang\n"
" Ravi Pinjala\n"
" Rodrigo Braz Monteiro\n"
" Simone Cociancich\n"
@ -129,7 +131,7 @@ void ShowAboutDialog(wxWindow *parent) {
wxChar copySymbol = 0xA9;
aboutString.Replace("(c)", wxString(copySymbol));
wxTextCtrl *textctrl = new wxTextCtrl(&d, -1, aboutString, wxDefaultPosition, wxSize(-1, 200), wxTE_MULTILINE | wxTE_READONLY | wxBORDER_NONE);
wxTextCtrl *textctrl = new wxTextCtrl(&d, -1, aboutString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxBORDER_NONE);
wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL);
MainSizer->Add(new wxStaticBitmap(&d, -1, GETIMAGE(splash)), 0, wxCENTER, 0);

378
src/dialog_align.cpp Normal file
View File

@ -0,0 +1,378 @@
// Copyright (c) 2019, Charlie Jiang
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
#include "ass_dialogue.h"
#include "ass_file.h"
#include "compat.h"
#include "dialog_manager.h"
#include "format.h"
#include "include/aegisub/context.h"
#include "video_frame.h"
#include "libresrc/libresrc.h"
#include "options.h"
#include "project.h"
#include "selection_controller.h"
#include "video_controller.h"
#include "async_video_provider.h"
#include "colour_button.h"
#include "image_position_picker.h"
#include <cmath>
#include <libaegisub/ass/time.h>
#include <libaegisub/vfr.h>
#include <wx/dialog.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#if BOOST_VERSION >= 106900
#include <boost/gil.hpp>
#else
#include <boost/gil/gil_all.hpp>
#endif
namespace {
class DialogAlignToVideo final : public wxDialog {
agi::Context* context;
AsyncVideoProvider* provider;
wxImage preview_image;
VideoFrame current_frame;
int current_n_frame;
ImagePositionPicker* preview_frame;
ColourButton* selected_color;
wxTextCtrl* selected_x;
wxTextCtrl* selected_y;
wxTextCtrl* selected_tolerance;
void update_from_textbox();
void update_from_textbox(wxCommandEvent&);
bool check_exists(int pos, int x, int y, int* lrud, double* orig, unsigned char tolerance);
void process(wxCommandEvent&);
public:
DialogAlignToVideo(agi::Context* context);
~DialogAlignToVideo();
};
DialogAlignToVideo::DialogAlignToVideo(agi::Context* context)
: wxDialog(context->parent, -1, _("Align subtitle to video by key point"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxMAXIMIZE_BOX | wxRESIZE_BORDER)
, context(context), provider(context->project->VideoProvider())
{
auto add_with_label = [&](wxSizer * sizer, wxString const& label, wxWindow * ctrl) {
sizer->Add(new wxStaticText(this, -1, label), 0, wxLEFT | wxRIGHT | wxCENTER, 3);
sizer->Add(ctrl, 1, wxLEFT);
};
auto tolerance = OPT_GET("Tool/Align to Video/Tolerance")->GetInt();
auto maximized = OPT_GET("Tool/Align to Video/Maximized")->GetBool();
current_n_frame = context->videoController->GetFrameN();
current_frame = *context->project->VideoProvider()->GetFrame(current_n_frame, 0, true);
preview_image = GetImage(current_frame);
preview_frame = new ImagePositionPicker(this, preview_image, [&](int x, int y, unsigned char r, unsigned char g, unsigned char b) -> void {
selected_x->ChangeValue(wxString::Format(wxT("%i"), x));
selected_y->ChangeValue(wxString::Format(wxT("%i"), y));
selected_color->SetColor(agi::Color(r, g, b));
});
selected_color = new ColourButton(this, wxSize(55, 16), true, agi::Color("FFFFFF"));
selected_color->SetToolTip(_("The key color to be followed."));
selected_x = new wxTextCtrl(this, -1, "0");
selected_x->SetToolTip(_("The x coord of the key point."));
selected_y = new wxTextCtrl(this, -1, "0");
selected_y->SetToolTip(_("The y coord of the key point."));
selected_tolerance = new wxTextCtrl(this, -1, wxString::Format(wxT("%i"), int(tolerance)));
selected_tolerance->SetToolTip(_("Max tolerance of the color."));
selected_x->Bind(wxEVT_TEXT, &DialogAlignToVideo::update_from_textbox, this);
selected_y->Bind(wxEVT_TEXT, &DialogAlignToVideo::update_from_textbox, this);
update_from_textbox();
wxFlexGridSizer* right_sizer = new wxFlexGridSizer(4, 2, 5, 5);
add_with_label(right_sizer, _("X"), selected_x);
add_with_label(right_sizer, _("Y"), selected_y);
add_with_label(right_sizer, _("Color"), selected_color);
add_with_label(right_sizer, _("Tolerance"), selected_tolerance);
right_sizer->AddGrowableCol(1, 1);
wxSizer* main_sizer = new wxBoxSizer(wxHORIZONTAL);
main_sizer->Add(preview_frame, 1, (wxALL & ~wxRIGHT) | wxEXPAND, 5);
main_sizer->Add(right_sizer, 0, wxALIGN_LEFT, 5);
wxSizer* dialog_sizer = new wxBoxSizer(wxVERTICAL);
dialog_sizer->Add(main_sizer, wxSizerFlags(1).Border(wxALL & ~wxBOTTOM).Expand());
dialog_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Right().Border());
SetSizerAndFit(dialog_sizer);
SetSize(1024, 700);
CenterOnParent();
Bind(wxEVT_BUTTON, &DialogAlignToVideo::process, this, wxID_OK);
SetIcon(GETICON(button_align_16));
if (maximized)
wxDialog::Maximize(true);
}
DialogAlignToVideo::~DialogAlignToVideo()
{
long lt;
if (!selected_tolerance->GetValue().ToLong(&lt))
return;
if (lt < 0 || lt > 255)
return;
OPT_SET("Tool/Align to Video/Tolerance")->SetInt(lt);
}
void rgb2lab(unsigned char r, unsigned char g, unsigned char b, double* lab)
{
double R = static_cast<double>(r) / 255.0;
double G = static_cast<double>(g) / 255.0;
double B = static_cast<double>(b) / 255.0;
double X = 0.412453 * R + 0.357580 * G + 0.180423 * B;
double Y = 0.212671 * R + 0.715160 * G + 0.072169 * B;
double Z = 0.019334 * R + 0.119193 * G + 0.950227 * B;
double xr = X / 0.950456, yr = Y / 1.000, zr = Z / 1.088854;
if (yr > 0.008856) {
lab[0] = 116.0 * pow(yr, 1.0 / 3.0) - 16.0;
}
else {
lab[0] = 903.3 * yr;
}
double fxr, fyr, fzr;
if (xr > 0.008856)
fxr = pow(xr, 1.0 / 3.0);
else
fxr = 7.787 * xr + 16.0 / 116.0;
if (yr > 0.008856)
fyr = pow(yr, 1.0 / 3.0);
else
fyr = 7.787 * yr + 16.0 / 116.0;
if (zr > 0.008856)
fzr = pow(zr, 1.0 / 3.0);
else
fzr = 7.787 * zr + 16.0 / 116.0;
lab[1] = 500.0 * (fxr - fyr);
lab[2] = 200.0 * (fyr - fzr);
}
template<typename T>
bool check_point(boost::gil::pixel<unsigned char, T> & pixel, double orig[3], unsigned char tolerance)
{
double lab[3];
// in pixel: B,G,R
rgb2lab(pixel[2], pixel[1], pixel[0], lab);
auto diff = sqrt(pow(lab[0] - orig[0], 2) + pow(lab[1] - orig[1], 2) + pow(lab[2] - orig[2], 2));
return diff < tolerance;
}
template<typename T>
bool calculate_point(boost::gil::image_view<T> view, int x, int y, double orig[3], unsigned char tolerance, int* ret)
{
auto origin = *view.at(x, y);
if (!check_point(origin, orig, tolerance))
return false;
auto w = view.width();
auto h = view.height();
int l = x, r = x, u = y, d = y;
for (int i = x + 1; i < w; i++)
{
auto p = *view.at(i, y);
if (!check_point(p, orig, tolerance))
{
r = i;
break;
}
}
for (int i = x - 1; i >= 0; i--)
{
auto p = *view.at(i, y);
if (!check_point(p, orig, tolerance))
{
l = i;
break;
}
}
for (int i = y + 1; i < h; i++)
{
auto p = *view.at(x, i);
if (!check_point(p, orig, tolerance))
{
d = i;
break;
}
}
for (int i = y - 1; i >= 0; i--)
{
auto p = *view.at(x, i);
if (!check_point(p, orig, tolerance))
{
u = i;
break;
}
}
ret[0] = l;
ret[1] = r;
ret[2] = u;
ret[3] = d;
return true;
}
void DialogAlignToVideo::process(wxCommandEvent & evt)
{
auto n_frames = provider->GetFrameCount();
auto w = provider->GetWidth();
auto h = provider->GetHeight();
long lx, ly, lt;
if (!selected_x->GetValue().ToLong(&lx) || !selected_y->GetValue().ToLong(&ly) || !selected_tolerance->GetValue().ToLong(&lt))
{
wxMessageBox(_("Bad x or y position or tolerance value!"));
evt.Skip();
return;
}
if (lx < 0 || ly < 0 || lx >= w || ly >= h)
{
wxMessageBox(wxString::Format(_("Bad x or y position! Require: 0 <= x < %i, 0 <= y < %i"), w, h));
evt.Skip();
return;
}
if (lt < 0 || lt > 255)
{
wxMessageBox(_("Bad tolerance value! Require: 0 <= torlerance <= 255"));
evt.Skip();
return;
}
int x = int(lx), y = int(ly);
unsigned char tolerance = (unsigned char)(lt);
auto color = selected_color->GetColor();
auto r = color.r;
auto b = color.b;
auto g = color.g;
double lab[3];
rgb2lab(r, g, b, lab);
int pos = current_n_frame;
auto frame = provider->GetFrame(pos, -1, true);
auto view = interleaved_view(frame->width, frame->height, reinterpret_cast<boost::gil::bgra8_pixel_t*>(frame->data.data()), frame->pitch);
if (frame->flipped)
y = frame->height - y;
int lrud[4];
calculate_point(view, x, y, lab, tolerance, lrud);
// find forward
#define CHECK_EXISTS_POS check_exists(pos, x, y, lrud, lab, tolerance)
while (pos >= 0)
{
if (CHECK_EXISTS_POS)
pos -= 2;
else break;
}
pos++;
pos = std::max(0, pos);
auto left = CHECK_EXISTS_POS ? pos : pos + 1;
pos = current_n_frame;
while (pos < n_frames)
{
if (CHECK_EXISTS_POS)
pos += 2;
else break;
}
pos--;
pos = std::min(pos, n_frames - 1);
auto right = CHECK_EXISTS_POS ? pos : pos - 1;
auto timecode = context->project->Timecodes();
auto line = context->selectionController->GetActiveLine();
line->Start = timecode.TimeAtFrame(left, agi::vfr::Time::START);
line->End = timecode.TimeAtFrame(right, agi::vfr::Time::END); // exclusive
context->ass->Commit(_("Align to video by key point"), AssFile::COMMIT_DIAG_TIME);
Close();
}
bool DialogAlignToVideo::check_exists(int pos, int x, int y, int* lrud, double* orig, unsigned char tolerance)
{
auto frame = provider->GetFrame(pos, -1, true);
auto view = interleaved_view(frame->width, frame->height, reinterpret_cast<boost::gil::bgra8_pixel_t*>(frame->data.data()), frame->pitch);
if (frame->flipped)
y = frame->height - y;
int actual[4];
if (!calculate_point(view, x, y, orig, tolerance, actual)) return false;
int dl = abs(actual[0] - lrud[0]);
int dr = abs(actual[1] - lrud[1]);
int du = abs(actual[2] - lrud[2]);
int dd = abs(actual[3] - lrud[3]);
return dl <= 5 && dr <= 5 && du <= 5 && dd <= 5;
}
void DialogAlignToVideo::update_from_textbox()
{
long lx, ly;
int w = preview_image.GetWidth(), h = preview_image.GetHeight();
if (!selected_x->GetValue().ToLong(&lx) || !selected_y->GetValue().ToLong(&ly))
return;
if (lx < 0 || ly < 0 || lx >= w || ly >= h)
return;
int x = int(lx);
int y = int(ly);
auto r = preview_image.GetRed(x, y);
auto g = preview_image.GetGreen(x, y);
auto b = preview_image.GetBlue(x, y);
selected_color->SetColor(agi::Color(r, g, b));
}
void DialogAlignToVideo::update_from_textbox(wxCommandEvent & evt)
{
update_from_textbox();
}
}
void ShowAlignToVideoDialog(agi::Context * c)
{
c->dialog->Show<DialogAlignToVideo>(c);
}

View File

@ -143,7 +143,7 @@ void DialogAutosave::Populate(std::map<wxString, AutosaveFile> &files_map, std::
auto it = files_map.find(name);
if (it == files_map.end())
it = files_map.insert({name, AutosaveFile{name}}).first;
it = files_map.insert({name, AutosaveFile{name, std::vector<Version>()}}).first;
it->second.versions.push_back(Version{wxFileName(directory, fn).GetFullPath(), date, agi::wxformat(name_fmt, date.Format())});
} while (dir.GetNext(&fn));
}

View File

@ -557,9 +557,9 @@ DialogColorPicker::DialogColorPicker(wxWindow *parent, agi::Color initial_color,
wxString modes[] = { _("RGB/R"), _("RGB/G"), _("RGB/B"), _("HSL/L"), _("HSV/H") };
colorspace_choice = new wxChoice(this, -1, wxDefaultPosition, wxDefaultSize, 5, modes);
wxSize colorinput_size = GetTextExtent(" &H10117B& ");
colorinput_size.SetHeight(-1);
wxSize colorinput_labelsize(40, -1);
ass_input = new wxTextCtrl(this, -1);
wxSize colorinput_size = ass_input->GetSizeFromTextSize(GetTextExtent(wxS("&H10117B&")));
ass_input->SetInitialSize(colorinput_size);
wxSizer *rgb_box = new wxStaticBoxSizer(wxHORIZONTAL, this, _("RGB color"));
wxSizer *hsl_box = new wxStaticBoxSizer(wxVERTICAL, this, _("HSL color"));
@ -568,7 +568,7 @@ DialogColorPicker::DialogColorPicker(wxWindow *parent, agi::Color initial_color,
for (auto& elem : rgb_input)
elem = new wxSpinCtrl(this, -1, "", wxDefaultPosition, colorinput_size, wxSP_ARROW_KEYS, 0, 255);
ass_input = new wxTextCtrl(this, -1, "", wxDefaultPosition, colorinput_size);
// ass_input = new wxTextCtrl(this, -1, "", wxDefaultPosition, colorinput_size);
html_input = new wxTextCtrl(this, -1, "", wxDefaultPosition, colorinput_size);
alpha_input = new wxSpinCtrl(this, -1, "", wxDefaultPosition, colorinput_size, wxSP_ARROW_KEYS, 0, 255);

View File

@ -72,19 +72,22 @@ static ResolutionShortcut resolutions[] = {
{"704x396 (SD widescreen)", 704, 396},
{"640x352 (SD widescreen MOD16)", 640, 352},
{"704x400 (SD widescreen MOD16)", 704, 400},
{"1024x576 (SuperPAL widescreen)", 1024, 576},
{"1280x720 (HD 720p)", 1280, 720},
{"1920x1080 (HD 1080p)", 1920, 1080},
{"1024x576 (SuperPAL widescreen)", 1024, 576}
{"1920x1080 (FHD 1080p)", 1920, 1080},
{"2560x1440 (QHD 1440p)", 2560, 1440},
{"3840x2160 (4K UHD 2160p)", 3840, 2160},
};
wxSpinCtrl *spin_ctrl(wxWindow *parent, int min, int max, int *value) {
auto ctrl = new wxSpinCtrl(parent, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, min, max, *value);
auto ctrl = new wxSpinCtrl(parent, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, *value);
ctrl->SetValidator(wxGenericValidator(value));
return ctrl;
}
// FIXME: change the misleading function name, this is TextCtrl in fact
wxControl *spin_ctrl(wxWindow *parent, double min, double max, double *value) {
return new wxTextCtrl(parent, -1, "", wxDefaultPosition, wxSize(50, -1), 0, DoubleValidator(value, min, max));
return new wxTextCtrl(parent, -1, "", wxDefaultPosition, wxDefaultSize, 0, DoubleValidator(value, min, max));
}
wxComboBox *resolution_shortcuts(wxWindow *parent, int width, int height) {

View File

@ -125,7 +125,7 @@ DialogExport::DialogExport(agi::Context *c)
wxButton *btn_none = new wxButton(&d, -1, _("Select &None"), wxDefaultPosition, wxSize(80, -1));
btn_up->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) { swap(filter_list, filter_list->GetSelection() - 1, 0); });
btn_down->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) { swap(filter_list, filter_list->GetSelection() - 1, 0); });
btn_down->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) { swap(filter_list, filter_list->GetSelection(), 1); });
btn_all->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) { SetAll(true); });
btn_none->Bind(wxEVT_BUTTON, [=](wxCommandEvent&) { SetAll(false); });

View File

@ -110,6 +110,7 @@ int ShowEbuExportConfigurationDialog(wxWindow *owner, EbuExportSettings &s) {
wxRadioBox *tv_standard_box = new wxRadioBox(&d, -1, _("TV standard"), wxDefaultPosition, wxDefaultSize, 6, tv_standards, 0, wxRA_SPECIFY_ROWS);
wxTextCtrl *timecode_offset_entry = new wxTextCtrl(&d, -1, "00:00:00:00");
timecode_offset_entry->SetInitialSize(timecode_offset_entry->GetSizeFromTextSize(timecode_offset_entry->GetTextExtent(wxS("00:00:00:00"))));
wxCheckBox *inclusive_end_times_check = new wxCheckBox(&d, -1, _("Out-times are inclusive"));
wxString text_encodings[] = {
@ -129,7 +130,8 @@ int ShowEbuExportConfigurationDialog(wxWindow *owner, EbuExportSettings &s) {
_("Skip lines that are too long")
};
wxSpinCtrl *max_line_length_ctrl = new wxSpinCtrl(&d, -1, wxString(), wxDefaultPosition, wxSize(65, -1));
wxSpinCtrl *max_line_length_ctrl = new wxSpinCtrl(&d, -1, wxString());
max_line_length_ctrl->SetInitialSize(max_line_length_ctrl->GetSizeFromTextSize(max_line_length_ctrl->GetTextExtent(wxS("00"))));
wxComboBox *wrap_mode_ctrl = new wxComboBox(&d, -1, wrap_modes[0], wxDefaultPosition, wxDefaultSize, 4, wrap_modes, wxCB_DROPDOWN | wxCB_READONLY);
wxCheckBox *translate_alignments_check = new wxCheckBox(&d, -1, _("Translate alignments"));

View File

@ -400,7 +400,11 @@ void DialogFontsCollector::OnAddText(ValueEvent<color_str_pair> &event) {
auto const& utf8 = str.second.utf8_str();
collection_log->AppendTextRaw(utf8.data(), utf8.length());
if (str.first) {
#if wxCHECK_VERSION (3, 1, 0)
collection_log->StartStyling(pos);
#else
collection_log->StartStyling(pos, 31);
#endif
collection_log->SetStyling(utf8.length(), str.first);
}
collection_log->GotoPos(pos + utf8.length());
@ -415,8 +419,7 @@ void DialogFontsCollector::OnCollectionComplete(wxThreadEvent &) {
if (path.Decode("?script") == "?script")
collection_mode->Enable(2, false);
wxCommandEvent evt;
OnRadio(evt);
UpdateControls();
}
}

View File

@ -108,8 +108,8 @@ DialogProperties::DialogProperties(agi::Context *c)
TopSizer->Add(TopSizerGrid,1,wxALL | wxEXPAND,0);
// Resolution box
ResX = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxSize(50,20),0,IntValidator(c->ass->GetScriptInfoAsInt("PlayResX")));
ResY = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxSize(50,20),0,IntValidator(c->ass->GetScriptInfoAsInt("PlayResY")));
ResX = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxDefaultSize,0,IntValidator(c->ass->GetScriptInfoAsInt("PlayResX")));
ResY = new wxTextCtrl(&d,-1,"",wxDefaultPosition,wxDefaultSize,0,IntValidator(c->ass->GetScriptInfoAsInt("PlayResY")));
wxButton *FromVideo = new wxButton(&d,-1,_("From &video"));
if (!c->project->VideoProvider())
@ -173,7 +173,7 @@ DialogProperties::DialogProperties(agi::Context *c)
}
void DialogProperties::AddProperty(wxSizer *sizer, wxString const& label, std::string const& property) {
wxTextCtrl *ctrl = new wxTextCtrl(&d, -1, to_wx(c->ass->GetScriptInfo(property)), wxDefaultPosition, wxSize(200, 20));
wxTextCtrl *ctrl = new wxTextCtrl(&d, -1, to_wx(c->ass->GetScriptInfo(property)));
sizer->Add(new wxStaticText(&d, -1, label), wxSizerFlags().Center().Left());
sizer->Add(ctrl, wxSizerFlags(1).Expand());
properties.push_back({property, ctrl});

View File

@ -112,7 +112,7 @@ DialogResample::DialogResample(agi::Context *c, ResampleSettings &settings)
// Create all controls and set validators
for (size_t i = 0; i < 4; ++i) {
margin_ctrl[i] = new wxSpinCtrl(&d, -1, "0", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, -9999, 9999, 0);
margin_ctrl[i] = new wxSpinCtrl(&d, -1, "0", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, -9999, 9999, 0);
margin_ctrl[i]->SetValidator(wxGenericValidator(&settings.margin[i]));
}
@ -122,12 +122,12 @@ DialogResample::DialogResample(agi::Context *c, ResampleSettings &settings)
margin_ctrl[RIGHT]->Enable(false);
margin_ctrl[BOTTOM]->Enable(false);
source_x = new wxSpinCtrl(&d, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, 1, INT_MAX);
source_y = new wxSpinCtrl(&d, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, 1, INT_MAX);
source_x = new wxSpinCtrl(&d, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, INT_MAX);
source_y = new wxSpinCtrl(&d, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, INT_MAX);
source_matrix = new wxComboBox(&d, -1, "", wxDefaultPosition,
wxDefaultSize, to_wx(MatrixNames()), wxCB_READONLY);
dest_x = new wxSpinCtrl(&d, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, 1, INT_MAX);
dest_y = new wxSpinCtrl(&d, -1, "", wxDefaultPosition, wxSize(50, -1), wxSP_ARROW_KEYS, 1, INT_MAX);
dest_x = new wxSpinCtrl(&d, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, INT_MAX);
dest_y = new wxSpinCtrl(&d, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, INT_MAX);
dest_matrix = new wxComboBox(&d, -1, "", wxDefaultPosition, wxDefaultSize,
to_wx(MatrixNames()), wxCB_READONLY);

View File

@ -151,7 +151,7 @@ DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Con
auto num_text_ctrl = [&](double *value, double min, double max, double step) -> wxSpinCtrlDouble * {
auto scd = new wxSpinCtrlDouble(this, -1, "", wxDefaultPosition,
wxSize(75, -1), wxSP_ARROW_KEYS, min, max, *value, step);
wxDefaultSize, wxSP_ARROW_KEYS, min, max, *value, step);
scd->SetValidator(DoubleSpinValidator(value));
scd->Bind(wxEVT_SPINCTRLDOUBLE, [=](wxSpinDoubleEvent &evt) {
evt.Skip();
@ -197,10 +197,12 @@ DialogStyleEditor::DialogStyleEditor(wxWindow *parent, AssStyle *style, agi::Con
new ColourButton(this, wxSize(55, 16), true, style->outline, ColorValidator(&work->outline)),
new ColourButton(this, wxSize(55, 16), true, style->shadow, ColorValidator(&work->shadow))
};
for (int i = 0; i < 3; i++)
for (int i = 0; i < 3; i++) {
margin[i] = new wxSpinCtrl(this, -1, std::to_wstring(style->Margin[i]),
wxDefaultPosition, wxSize(60, -1),
wxSP_ARROW_KEYS, 0, 9999, style->Margin[i]);
wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS, 0, 9999, style->Margin[i]);
margin[i]->SetInitialSize(margin[i]->GetSizeFromTextSize(GetTextExtent(wxS("0000"))));
}
Alignment = new wxRadioBox(this, -1, _("Alignment"), wxDefaultPosition, wxDefaultSize, 9, alignValues, 3, wxRA_SPECIFY_COLS);
auto Outline = num_text_ctrl(&work->outline_w, 0.0, 1000.0, 0.1);

View File

@ -144,8 +144,8 @@ DialogTimingProcessor::DialogTimingProcessor(agi::Context *c)
d.SetIcon(GETICON(timing_processor_toolbutton_16));
// Read options
leadIn = OPT_GET("Audio/Lead/IN")->GetInt();
leadOut = OPT_GET("Audio/Lead/OUT")->GetInt();
leadIn = OPT_GET("Tool/Timing Post Processor/Lead/IN")->GetInt();
leadOut = OPT_GET("Tool/Timing Post Processor/Lead/OUT")->GetInt();
beforeStart = OPT_GET("Tool/Timing Post Processor/Threshold/Key Start Before")->GetInt();
beforeEnd = OPT_GET("Tool/Timing Post Processor/Threshold/Key End Before")->GetInt();
afterStart = OPT_GET("Tool/Timing Post Processor/Threshold/Key Start After")->GetInt();
@ -305,8 +305,8 @@ void DialogTimingProcessor::UpdateControls() {
void DialogTimingProcessor::OnApply(wxCommandEvent &) {
d.TransferDataFromWindow();
// Save settings
OPT_SET("Audio/Lead/IN")->SetInt(leadIn);
OPT_SET("Audio/Lead/OUT")->SetInt(leadOut);
OPT_SET("Tool/Timing Post Processor/Lead/IN")->SetInt(leadIn);
OPT_SET("Tool/Timing Post Processor/Lead/OUT")->SetInt(leadOut);
OPT_SET("Tool/Timing Post Processor/Threshold/Key Start Before")->SetInt(beforeStart);
OPT_SET("Tool/Timing Post Processor/Threshold/Key Start After")->SetInt(afterStart);
OPT_SET("Tool/Timing Post Processor/Threshold/Key End Before")->SetInt(beforeEnd);

View File

@ -31,6 +31,7 @@
#include "format.h"
#include "help_button.h"
#include "libresrc/libresrc.h"
#include "options.h"
#include "persist_location.h"
#include "project.h"
#include "subs_edit_ctrl.h"
@ -57,7 +58,8 @@ static void add_hotkey(wxSizer *sizer, wxWindow *parent, const char *command, wx
// Skip over override blocks, comments, and whitespace between blocks
static bool bad_block(std::unique_ptr<AssDialogueBlock> &block) {
return block->GetType() != AssBlockType::PLAIN || boost::all(block->GetText(), boost::is_space());
bool is_whitespace = boost::all(block->GetText(), boost::is_space());
return block->GetType() != AssBlockType::PLAIN || (is_whitespace && OPT_GET("Tool/Translation Assistant/Skip Whitespace")->GetBool());
}
DialogTranslation::DialogTranslation(agi::Context *c)
@ -95,7 +97,11 @@ DialogTranslation::DialogTranslation(agi::Context *c)
translated_text->SetMarginWidth(1, 0);
translated_text->SetFocus();
translated_text->Bind(wxEVT_CHAR_HOOK, &DialogTranslation::OnKeyDown, this);
#if wxCHECK_VERSION (3, 1, 0)
translated_text->CmdKeyAssign(wxSTC_KEY_RETURN, wxSTC_KEYMOD_SHIFT, wxSTC_CMD_NEWLINE);
#else
translated_text->CmdKeyAssign(wxSTC_KEY_RETURN, wxSTC_SCMOD_SHIFT, wxSTC_CMD_NEWLINE);
#endif
wxSizer *translated_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Translation"));
translated_box->Add(translated_text, 1, wxEXPAND, 0);
@ -244,7 +250,11 @@ void DialogTranslation::UpdateDisplay() {
int initial_pos = original_text->GetLength();
original_text->AppendTextRaw(block->GetText().c_str());
if (i == cur_block) {
#if wxCHECK_VERSION (3, 1, 0)
original_text->StartStyling(initial_pos);
#else
original_text->StartStyling(initial_pos, 31);
#endif
original_text->SetStyling(block->GetText().size(), 1);
}
}

View File

@ -131,7 +131,6 @@ bool update_video_properties(AssFile *file, const AsyncVideoProvider *new_provid
return true;
case MISMATCH_RESAMPLE:
// Fallthrough to prompt if the AR changed
if (!ar_changed) {
ResampleResolution(file, {
{0, 0, 0, 0},
@ -141,6 +140,8 @@ bool update_video_properties(AssFile *file, const AsyncVideoProvider *new_provid
});
return true;
}
// Fallthrough
// to prompt if the AR changed
case MISMATCH_PROMPT:
int res = prompt(parent, ar_changed, sx, sy, vx, vy);

View File

@ -74,3 +74,4 @@ void ShowSpellcheckerDialog(agi::Context *c);
void ShowStyleManagerDialog(agi::Context *c);
void ShowTimingProcessorDialog(agi::Context *c);
void ShowVideoDetailsDialog(agi::Context *c);
void ShowAlignToVideoDialog(agi::Context* c);

9
src/dpi_aware.manifest Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>

View File

@ -78,9 +78,9 @@ wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent, a
initialInput = "23.976";
FromVideo->Enable(false);
}
InputFramerate = new wxTextCtrl(base,-1,initialInput,wxDefaultPosition,wxSize(60,20));
InputSizer->Add(InputFramerate,0,wxEXPAND | wxLEFT,5);
InputSizer->Add(FromVideo,0,wxEXPAND | wxLEFT,5);
InputFramerate = new wxTextCtrl(base,-1,initialInput);
InputSizer->Add(InputFramerate, 0, wxEXPAND);
InputSizer->Add(FromVideo, 0, wxEXPAND | wxLEFT, 5);
InputSizer->AddStretchSpacer(1);
// Output sizers
@ -90,7 +90,7 @@ wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent, a
// Output top line
RadioOutputVFR = new wxRadioButton(base,-1,_("V&ariable"),wxDefaultPosition,wxDefaultSize,wxRB_GROUP);
OutputSizerTop->Add(RadioOutputVFR,0,wxEXPAND,0);
OutputSizerTop->Add(RadioOutputVFR, wxEXPAND);
// Output bottom line
RadioOutputCFR = new wxRadioButton(base,-1,_("&Constant: "));
@ -99,9 +99,9 @@ wxWindow *AssTransformFramerateFilter::GetConfigDialogWindow(wxWindow *parent, a
RadioOutputVFR->Enable(false);
RadioOutputCFR->SetValue(true);
}
OutputFramerate = new wxTextCtrl(base,-1,initialOutput,wxDefaultPosition,wxSize(60,20));
OutputSizerBottom->Add(RadioOutputCFR,0,wxEXPAND,0);
OutputSizerBottom->Add(OutputFramerate,0,wxEXPAND | wxLEFT,5);
OutputFramerate = new wxTextCtrl(base,-1,initialOutput);
OutputSizerBottom->Add(RadioOutputCFR, wxEXPAND);
OutputSizerBottom->Add(OutputFramerate, 0, wxEXPAND | wxLEFT, 5);
OutputSizerBottom->AddStretchSpacer(1);
// Reverse checkbox

View File

@ -67,7 +67,7 @@ enum {
FFmpegSourceProvider::FFmpegSourceProvider(agi::BackgroundRunner *br)
: br(br)
{
FFMS_Init(0, 1);
FFMS_Init(0, 0);
}
/// @brief Does indexing of a source file

View File

@ -66,28 +66,30 @@ std::vector<agi::fs::path> get_installed_fonts() {
std::vector<agi::fs::path> files;
HKEY key;
auto ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fonts_key_name, 0, KEY_QUERY_VALUE, &key);
if (ret != ERROR_SUCCESS) return files;
BOOST_SCOPE_EXIT_ALL(=) { RegCloseKey(key); };
wchar_t fdir[MAX_PATH];
SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, fdir);
agi::fs::path font_dir(fdir);
for (DWORD i = 0;; ++i) {
wchar_t font_name[SHRT_MAX], font_filename[MAX_PATH];
DWORD name_len = sizeof(font_name);
DWORD data_len = sizeof(font_filename);
ret = RegEnumValueW(key, i, font_name, &name_len, NULL, NULL, reinterpret_cast<BYTE *>(font_filename), &data_len);
if (ret == ERROR_NO_MORE_ITEMS) break;
for (HKEY hKey : { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }) {
HKEY key;
auto ret = RegOpenKeyExW(hKey, fonts_key_name, 0, KEY_QUERY_VALUE, &key);
if (ret != ERROR_SUCCESS) continue;
BOOST_SCOPE_EXIT_ALL(= ) { RegCloseKey(key); };
agi::fs::path font_path(font_filename);
if (!agi::fs::FileExists(font_path))
font_path = font_dir / font_path;
files.push_back(font_path);
wchar_t fdir[MAX_PATH];
SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, fdir);
agi::fs::path font_dir(fdir);
for (DWORD i = 0;; ++i) {
wchar_t font_name[SHRT_MAX], font_filename[MAX_PATH];
DWORD name_len = sizeof(font_name);
DWORD data_len = sizeof(font_filename);
ret = RegEnumValueW(key, i, font_name, &name_len, NULL, NULL, reinterpret_cast<BYTE*>(font_filename), &data_len);
if (ret == ERROR_NO_MORE_ITEMS) break;
if (ret != ERROR_SUCCESS) continue;
agi::fs::path font_path(font_filename);
if (!agi::fs::FileExists(font_path) && agi::fs::FileExists(font_dir / font_path))
font_path = font_dir / font_path;
files.push_back(font_path);
}
}
return files;

View File

@ -74,7 +74,7 @@ enum {
};
#ifdef WITH_STARTUPLOG
#define StartupLog(a) MessageBox(0, a, "Aegisub startup log", 0)
#define StartupLog(a) wxMessageBox(a, "Aegisub startup log")
#else
#define StartupLog(a) LOG_I("frame_main/init") << a
#endif
@ -240,8 +240,6 @@ void FrameMain::SetDisplayMode(int video, int audio) {
TopSizer->Show(videoBox, showVideo, true);
ToolsSizer->Show(audioBox, showAudio, true);
MainSizer->CalcMin();
MainSizer->RecalcSizes();
MainSizer->Layout();
Layout();

File diff suppressed because it is too large Load Diff

View File

@ -52,10 +52,9 @@
#include <GL/gl.h>
#endif
namespace {
/// @class OpenGLTextGlyph
/// @brief Struct storing the information needed to draw a glyph
struct OpenGLTextGlyph {
struct OpenGLText::OpenGLTextGlyph {
wxString str; ///< String containing the glyph(s) this is for
int tex = 0; ///< OpenGL texture to draw for this glyph
float x1 = 0; ///< Left x coordinate of this glyph in the containing texture
@ -108,7 +107,7 @@ struct OpenGLTextGlyph {
/// @class OpenGLTextTexture
/// @brief OpenGL texture which stores one or more glyphs as sprites
class OpenGLTextTexture final : boost::noncopyable {
class OpenGLText::OpenGLTextTexture final : boost::noncopyable {
int x = 0; ///< Next x coordinate at which a glyph can be inserted
int y = 0; ///< Next y coordinate at which a glyph can be inserted
int nextY = 0; ///< Y coordinate of the next line; tracked due to that lines
@ -217,8 +216,6 @@ public:
}
};
}
OpenGLText::OpenGLText() { }
OpenGLText::~OpenGLText() { }
@ -286,12 +283,12 @@ void OpenGLText::GetExtent(std::string const& text, int &w, int &h) {
}
}
OpenGLTextGlyph const& OpenGLText::GetGlyph(int i) {
OpenGLText::OpenGLTextGlyph const& OpenGLText::GetGlyph(int i) {
auto res = glyphs.find(i);
return res != glyphs.end() ? res->second : CreateGlyph(i);
}
OpenGLTextGlyph const& OpenGLText::CreateGlyph(int n) {
OpenGLText::OpenGLTextGlyph const& OpenGLText::CreateGlyph(int n) {
OpenGLTextGlyph &glyph = glyphs.emplace(n, OpenGLTextGlyph(n, font)).first->second;
// Insert into some texture

View File

@ -34,16 +34,13 @@
#include <wx/font.h>
namespace {
struct OpenGLTextGlyph;
class OpenGLTextTexture;
}
namespace agi { struct Color; }
typedef boost::container::map<int, OpenGLTextGlyph> glyphMap;
class OpenGLText {
struct OpenGLTextGlyph;
class OpenGLTextTexture;
typedef boost::container::map<int, OpenGLTextGlyph> glyphMap;
float r = 1.f, g = 1.f, b = 1.f, a = 1.f;
int fontSize = 0;

View File

@ -28,7 +28,11 @@
#include <OpenGL/glext.h>
#else
#include <GL/gl.h>
#include "gl/glext.h"
#endif
#ifndef GL_GLEXT_VERSION
// The following typedef is copied from glext.h
typedef void (*PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint* first, const GLsizei* count, GLsizei drawcount);
#endif
static const float deg2rad = 3.1415926536f / 180.f;

View File

@ -29,6 +29,11 @@
#include <wx/msgdlg.h>
namespace {
const char* added_hotkeys_cj[][3] = {
{"time/align", "Video", "KP_TAB"},
{nullptr}
};
const char *added_hotkeys_7035[][3] = {
{"audio/play/line", "Audio", "R"},
{nullptr}
@ -47,10 +52,12 @@ namespace {
{nullptr}
};
#ifdef __WXMAC__
const char *added_hotkeys_minimize[][3] = {
{"app/minimize", "Default", "Ctrl-M"},
{nullptr}
};
#endif
void migrate_hotkeys(const char *added[][3]) {
auto hk_map = hotkey::inst->GetHotkeyMap();
@ -81,6 +88,11 @@ void init() {
auto migrations = OPT_GET("App/Hotkey Migrations")->GetListString();
if (boost::find(migrations, "cj") == end(migrations)) {
migrate_hotkeys(added_hotkeys_cj);
migrations.emplace_back("cj");
}
if (boost::find(migrations, "7035") == end(migrations)) {
migrate_hotkeys(added_hotkeys_7035);
migrations.emplace_back("7035");

View File

@ -0,0 +1,127 @@
#include "image_position_picker.h"
BEGIN_EVENT_TABLE(ImagePositionPicker, wxPanel)
// some useful events
/*
EVT_MOTION(ImagePositionPicker::mouseMoved)
EVT_LEFT_DOWN(ImagePositionPicker::mouseDown)
EVT_LEFT_UP(ImagePositionPicker::mouseReleased)
EVT_RIGHT_DOWN(ImagePositionPicker::rightClick)
EVT_LEAVE_WINDOW(ImagePositionPicker::mouseLeftWindow)
EVT_KEY_DOWN(ImagePositionPicker::keyPressed)
EVT_KEY_UP(ImagePositionPicker::keyReleased)
EVT_MOUSEWHEEL(ImagePositionPicker::mouseWheelMoved)
*/
// catch paint events
EVT_PAINT(ImagePositionPicker::paintEvent)
//Size event
EVT_SIZE(ImagePositionPicker::OnSize)
EVT_MOUSE_EVENTS(ImagePositionPicker::OnMouseEvent)
END_EVENT_TABLE()
// some useful events
/*
void ImagePositionPicker::mouseMoved(wxMouseEvent& event) {}
void ImagePositionPicker::mouseDown(wxMouseEvent& event) {}
void ImagePositionPicker::mouseWheelMoved(wxMouseEvent& event) {}
void ImagePositionPicker::mouseReleased(wxMouseEvent& event) {}
void ImagePositionPicker::rightClick(wxMouseEvent& event) {}
void ImagePositionPicker::mouseLeftWindow(wxMouseEvent& event) {}
void ImagePositionPicker::keyPressed(wxKeyEvent& event) {}
void ImagePositionPicker::keyReleased(wxKeyEvent& event) {}
*/
ImagePositionPicker::ImagePositionPicker(wxWindow* parent, wxImage i, updator upd) : wxPanel(parent)
{
image = i;
prevW = -1;
prevH = -1;
w = image.GetWidth();
h = image.GetHeight();
update = upd;
}
/*
* Called by the system of by wxWidgets when the panel needs
* to be redrawn. You can also trigger this call by
* calling Refresh()/Update().
*/
void ImagePositionPicker::paintEvent(wxPaintEvent& evt)
{
// depending on your system you may need to look at double-buffered dcs
wxPaintDC dc(this);
render(dc);
}
/*
* Alternatively, you can use a clientDC to paint on the panel
* at any time. Using this generally does not free you from
* catching paint events, since it is possible that e.g. the window
* manager throws away your drawing when the window comes to the
* background, and expects you will redraw it when the window comes
* back (by sending a paint event).
*/
void ImagePositionPicker::paintNow()
{
// depending on your system you may need to look at double-buffered dcs
wxClientDC dc(this);
render(dc);
}
/*
* Here we do the actual rendering. I put it in a separate
* method so that it can work no matter what type of DC
* (e.g. wxPaintDC or wxClientDC) is used.
*/
void ImagePositionPicker::render(wxDC& dc)
{
int neww, newh;
dc.GetSize(&neww, &newh);
if (neww != prevW || newh != prevH)
{
// keep the image proportionate
int ww, hh;
if (double(neww) / w >= double(newh) / h) // too long
{
ww = newh * w / h;
hh = newh;
}
else
{
ww = neww;
hh = neww * h / w;
}
resized = wxBitmap(image.Scale(ww, hh /*, wxIMAGE_QUALITY_HIGH*/));
prevW = ww;
prevH = hh;
dc.DrawBitmap(resized, 0, 0, false);
}
else {
dc.DrawBitmap(resized, 0, 0, false);
}
}
/*
* Here we call refresh to tell the panel to draw itself again.
* So when the user resizes the image panel the image should be resized too.
*/
void ImagePositionPicker::OnSize(wxSizeEvent& event) {
Refresh();
//skip the event.
event.Skip();
}
void ImagePositionPicker::OnMouseEvent(wxMouseEvent& evt)
{
wxPoint pos = evt.GetPosition();
if (evt.Dragging() || evt.LeftDown() || evt.LeftUp())
{
int x = pos.x * w / prevW;
int y = pos.y * h / prevH;
if (x >= 0 && x < w && y >= 0 && y < h)
update(x, y, image.GetRed(x, y), image.GetGreen(x, y), image.GetBlue(x, y));
}
}

View File

@ -0,0 +1,37 @@
#include <wx/wx.h>
#include <wx/sizer.h>
#include "gl_wrap.h"
typedef std::function<void(double, double, unsigned char, unsigned char, unsigned char)> updator;
class ImagePositionPicker : public wxPanel
{
wxImage image;
wxBitmap resized;
int prevW, prevH, w, h;
updator update;
public:
ImagePositionPicker(wxWindow* parent, wxImage i, updator upd);
void paintEvent(wxPaintEvent & evt);
void paintNow();
void OnSize(wxSizeEvent& event);
void OnMouseEvent(wxMouseEvent& evt);
void render(wxDC& dc);
// some useful events
/*
void mouseMoved(wxMouseEvent& event);
void mouseDown(wxMouseEvent& event);
void mouseWheelMoved(wxMouseEvent& event);
void mouseReleased(wxMouseEvent& event);
void rightClick(wxMouseEvent& event);
void mouseLeftWindow(wxMouseEvent& event);
void keyPressed(wxKeyEvent& event);
void keyReleased(wxKeyEvent& event);
*/
DECLARE_EVENT_TABLE()
};

View File

@ -31,5 +31,5 @@ public:
InitialLineState(agi::Context *c);
std::string const& GetInitialText() const { return initial_text; }
DEFINE_SIGNAL_ADDERS(InitialStateChanged, AddChangeListener);
DEFINE_SIGNAL_ADDERS(InitialStateChanged, AddChangeListener)
};

View File

@ -40,24 +40,24 @@
"Display" : {
"Draw" : {
"Cursor Time" : true,
"Inactive Comments" : true,
"Inactive Comments" : false,
"Keyframes in Dialogue Mode" : true,
"Keyframes in Karaoke Mode" : true,
"Seconds" : false,
"Video Position" : false
"Seconds" : true,
"Video Position" : true
},
"Waveform Style" : 0
},
"Downmixer" : "ConvertToMono",
"Drag Timing" : true,
"Inactive Lines Display Mode" : 1,
"Inactive Lines Display Mode" : 3,
"Karaoke" : {
"Font Face" : "Verdana",
"Font Size" : 9
},
"Lead" : {
"IN" : 200,
"OUT" : 300
"IN" : 100,
"OUT" : 350
},
"Line Boundaries Thickness" : 2,
"Link" : true,
@ -75,11 +75,11 @@
}
},
"Snap" : {
"Distance" : 10,
"Enable" : false
"Distance" : 8,
"Enable" : true
},
"Spectrum" : true,
"Start Drag Sensitivity" : 3,
"Start Drag Sensitivity" : 8,
"Track Cursor" : {
"Font Face" : ""
},
@ -266,6 +266,13 @@
},
"Video Dummy" : {
"Last Colour" : "rgb(47, 163, 254)"
},
"Visual Tools" : {
"Highlight Primary" : "rgb(255, 169, 40)",
"Highlight Secondary" : "rgb(255, 253, 185)",
"Lines Primary" : "rgb(187, 0, 0)",
"Lines Secondary" : "rgb(106, 32, 19)",
"Shaded Area Alpha" : 0.5
}
},
@ -421,7 +428,7 @@
},
"Timing" : {
"Default Duration" : 2000
"Default Duration" : 3000
},
"Tool" : {
@ -545,6 +552,10 @@
}
},
"Only Selection" : false,
"Lead" : {
"IN" : 100,
"OUT" : 350
},
"Threshold" : {
"Adjacent Gap" : 300,
"Adjacent Overlap" : 50,
@ -559,10 +570,15 @@
"X" : -1,
"Y" : -1
},
"Maximized" : false
"Maximized" : false,
"Skip Whitespace" : true
},
"Visual" : {
"Autohide": false
},
"Align to Video" : {
"Tolerance" : 20,
"Maximized" : true
}
},
@ -584,13 +600,12 @@
"Dummy" : {
"FPS" : 23.975999999999999091,
"Last" : {
"Height" : 480,
"Height" : 720,
"Length" : 40000,
"Width" : 640
"Width" : 1280
},
"Pattern" : false
},
"Force BT.601" : true,
"Last Script Resolution Mismatch Choice" : 2,
"Open Audio" : true,
"Overscan Mask" : false,

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